71

I'm looking for some examples of how to securely store passwords and other sensitive data using node.js and mongodb.

I want everything to use a unique salt that I will store along side the hash in the mongo document.

For authentication do I have to just salt and encrypt the input and match it to a stored hash?

Should I ever need to decrypt this data and if so how should I do it?

How are the private keys, or even salting methods securely stored on the server?

I've heard the AES and Blowfish are both good options, what should I use?

Any examples of how to design this would be wonderfully helpful!

Thanks!

FS_aspirer
  • 83
  • 1
  • 12
fancy
  • 48,619
  • 62
  • 153
  • 231
  • possible duplicate of [Preferred Method of Storing Passwords In Database](http://stackoverflow.com/questions/615704/preferred-method-of-storing-passwords-in-database) – Thilo Aug 05 '11 at 04:51
  • https://github.com/bnoguchi/mongoose-auth/? – Alfred Aug 05 '11 at 07:05

2 Answers2

35

Use this: https://github.com/ncb000gt/node.bcrypt.js/

bcrypt is one of just a few algorithms focused on this use case. You should never be able to decrypt your passwords, only verify that a user-entered cleartext password matches the stored/encrypted hash.

bcrypt is very straightforward to use. Here is a snippet from my Mongoose User schema (in CoffeeScript). Be sure to use the async functions as bycrypt is slow (on purpose).

class User extends SharedUser
  defaults: _.extend {domainId: null}, SharedUser::defaults

  #Irrelevant bits trimmed...

  password: (cleartext, confirm, callback) ->
    errorInfo = new errors.InvalidData()
    if cleartext != confirm
      errorInfo.message = 'please type the same password twice'
      errorInfo.errors.confirmPassword = 'must match the password'
      return callback errorInfo
    message = min4 cleartext
    if message
      errorInfo.message = message
      errorInfo.errors.password = message
      return callback errorInfo
    self = this
    bcrypt.gen_salt 10, (error, salt)->
      if error
        errorInfo = new errors.InternalError error.message
        return callback errorInfo
      bcrypt.encrypt cleartext, salt, (error, hash)->
        if error
          errorInfo = new errors.InternalError error.message
          return callback errorInfo
        self.attributes.bcryptedPassword = hash
        return callback()

  verifyPassword: (cleartext, callback) ->
    bcrypt.compare cleartext, @attributes.bcryptedPassword, (error, result)->
      if error
        return callback(new errors.InternalError(error.message))
      callback null, result

Also, read this article, which should convince you that bcrypt is a good choice and help you avoid becoming "well and truly effed".

Peter Lyons
  • 142,938
  • 30
  • 279
  • 274
  • 1
    I'm not 100% sure that I buy into the logic of using bcrypt just because it's slow, as the article notes. There's no reason you can't use a much more "standard" and widely used algorithm like SHA-256 and just impose artificial latency on your system. Just wait for a quarter of a second before the server actually checks the hash passed in. Some systems also impose a user lockout (or reduced privilege) protocol if they get their password wrong x times within y hours. That comes with certain baggage, but it's an option to consider. – d512 Jun 06 '13 at 17:24
  • 20
    You are missing the point. The point is if an attacker steals your database of password hashes, bcrypt is slow for the attacker to run on their system, and there's no way around that because the work factor is built into the algorithm itself. SHA-256 plus artificial latency is A) using a general purpose hashing algorithm and B) not protecting you against offline cracking of stolen password hashes. – Peter Lyons Jun 10 '13 at 02:55
  • Yes, in a scenario in which the attacker actually was able to get a copy of all password hashes, they would have a harder time cracking them under bcrypt. The article does not specifically mention this case but it probably should. – d512 Jun 10 '13 at 16:34
13

This is the best example I've come across to date, uses node.bcrypt.js http://devsmash.com/blog/password-authentication-with-mongoose-and-bcrypt

chovy
  • 72,281
  • 52
  • 227
  • 295