Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save johan--/b70bd301bd2baa41b621 to your computer and use it in GitHub Desktop.
Save johan--/b70bd301bd2baa41b621 to your computer and use it in GitHub Desktop.

Encrypting text fields in Mongoose is easy using Node's built-in crypto module. You might want to do this if you're using MongoDB as a service (see the recent MongoHQ security breach); or, if you're storing OAuth tokens that could, in the wrong hands, screw with somebody's account on a 3rd party service. (Of course, you should never encrypt passwords: those should be hashed.)

Imagine you have a Mongoose model like that shown below, which is modified only slighly from the example on the MongooseJS homepage.

var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/test');

var User = mongoose.model('User', {
  name: String,
  twitterOAuthToken: String
});

var kyle = new User({
  name: 'Kyle',
  twitterOAuthToken: 'c2721fee51e7ee571105e2d56c4919ae18fb7519'
});

kyle.save(function (err) {
  console.log('woot');
});

If Kyle's twitterOAuthToken fell into the wrong hands, it may be used to send spam, or worse. To decrease that risk, we can store the token encrypted, decrypting it only in the application (in memory) using MongooseJS getters and setters. See the same code, below, in which I'm using an environment variable SERVER_SECRET as the key for AES-256 encryption in CBC mode.

var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/test');

// Here's the required crypto code
var crypto = require('crypto');

function encrypt(text){
  var cipher = crypto.createCipher('aes-256-cbc', process.env.SERVER_SECRET);
  var crypted = cipher.update(text,'utf8','hex');
  crypted += cipher.final('hex');
  return crypted;
} 

function decrypt(text){
  if (text === null || typeof text === 'undefined') {return text;};
  var decipher = crypto.createDecipher('aes-256-cbc', process.env.SERVER_SECRET);
  var dec = decipher.update(text,'hex','utf8');
  dec += decipher.final('utf8');
  return dec;
}

var User = mongoose.model('User', {
  name: String,
  // Now add a getter and a setter
  twitterOAuthToken: {type: String, get: decrypt, set: encrypt}
});

var kyle = new User({
  name: 'Kyle',
  twitterOAuthToken: 'c2721fee51e7ee571105e2d56c4919ae18fb7519'
});

kyle.save(function (err) {
  console.log('woot');
});

Now, whenever we set the model's twitterOAuthToken attribute, it is automatically encrypted, and when we access that attribute it is automatically decrypted. Only the encrypted value is sent to, and stored in, our MongoDB instance. That value is useless without the SERVER_SECRET.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment