Last active
October 10, 2020 18:55
-
-
Save tsmx/d6a19f8e71bf764a2563dd6a2bd22a4d to your computer and use it in GitHub Desktop.
Encryption-at-rest in MongoDB with Mongoose getters/setters and NodeJS Crypto.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const crypto = require('crypto'); | |
const algorithm = 'aes-256-cbc'; | |
const dbURI = 'mongodb://localhost/encryptiontest'; | |
const dbOptions = { | |
user: 'encryptiontest', | |
pass: 'test', | |
useNewUrlParser: true, | |
useCreateIndex: true, | |
useFindAndModify: false, | |
useUnifiedTopology: true | |
}; | |
function encrypt(text) { | |
let key = process.env.ENCRYPTION_KEY; | |
let iv = crypto.randomBytes(16); | |
let cipher = crypto.createCipheriv(algorithm, key, iv); | |
let encrypted = cipher.update(text); | |
encrypted = Buffer.concat([encrypted, cipher.final()]); | |
return iv.toString('hex') + '|' + encrypted.toString('hex'); | |
}; | |
function decrypt(text) { | |
let key = process.env.ENCRYPTION_KEY; | |
let decrypted = null; | |
try { | |
let input = text.split('|'); | |
let iv = Buffer.from(input[0], 'hex'); | |
let encryptedText = Buffer.from(input[1], 'hex'); | |
let decipher = crypto.createDecipheriv(algorithm, key, iv); | |
decrypted = decipher.update(encryptedText); | |
decrypted = Buffer.concat([decrypted, decipher.final()]); | |
} | |
catch (error) { | |
throw new Error('Decryption failed. Please check that the encrypted secret is valid'); | |
} | |
return decrypted.toString(); | |
}; | |
var mongoose = require('mongoose'); | |
var Visitor = mongoose.model('Visitor', { | |
firstName: { type: String, get: decrypt, set: encrypt }, | |
lastName: { type: String, get: decrypt, set: encrypt }, | |
}); | |
process.env.ENCRYPTION_KEY = '00000000000000000000000000000000'; | |
mongoose.connect(dbURI, dbOptions); | |
mongoose.connection.once('open', async function () { | |
const visitor = new Visitor(); | |
visitor.firstName = 'Hans'; | |
visitor.lastName = 'Müller'; | |
let savedVisitor = await visitor.save(); | |
console.log('=== save ==='); | |
console.log('Saved ID: ' + savedVisitor._id.toString()); | |
let retrievedVisitor = await Visitor.findById(savedVisitor._id); | |
console.log('=== findById (proove successful decryption) ==='); | |
console.log('Found ID: ' + retrievedVisitor._id.toString()); | |
console.log('Found firstName: ' + retrievedVisitor.firstName); | |
console.log('Found firstName: ' + retrievedVisitor.lastName); | |
let retrievedVisitorLean = await Visitor.findById(savedVisitor._id).lean(); | |
console.log('=== findById.lean (proove encryption-at-rest) ==='); | |
console.log('Lean ID: ' + retrievedVisitorLean._id); | |
console.log('Lean firstName: ' + retrievedVisitorLean.firstName); | |
console.log('Lean firstName: ' + retrievedVisitorLean.lastName); | |
mongoose.connection.close(function () { | |
process.exit(0); | |
}); | |
}); | |
// example output: | |
// | |
// === save === | |
// Saved ID: 5f80d1ceafd13c33ef94312c | |
// === findById (proove successful decryption) === | |
// Found ID: 5f80d1ceafd13c33ef94312c | |
// Found firstName: Hans | |
// Found firstName: Müller | |
// === findById.lean (proove encryption-at-rest) === | |
// Lean ID: 5f80d1ceafd13c33ef94312c | |
// Lean firstName: 54859787d74b8dac37a741265c608c16|585d9c05937ea833bcc7c9282e8f41db | |
// Lean firstName: c4f03e01125061b7341f6dcac97f2bd1|eb1016dff587de0bf80daa91ecf2771f |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment