Ruby on Rails Password Hashing Module

This is a very simple password module that is also easy to use. Simpy place it in /lib inside your Ruby on Rails application and start protecting your passwords today. This code uses a long hash, and creates individual salts for each password stored. It should be very computationally expensive for someone to crack every password in your database, were they to fall into the wrong hands. Of course, if your database is in the wrong hands, you probably have bigger problems. But even some large sites have been caught storing passwords in plain text.

Ruby Password Hashing Code

Usage

Using the the password module is simple. All you need to do is save the file above as “password.rb” in the lib directory of your rails project. Then require_dependency “password” in your application.rb. Once that is done you are free to use the functions in any controller.

Example

application.rb

account_controller.rb

This is an example account controller.

 

user.rb

This is the model for the user class. As you can see, password checking against a hashed password is very simple here. Authenicating the user returns a User object, which is stored in the session[:user] variable in the controller above.

19 Responses to “Ruby on Rails Password Hashing Module”

  1. Andy Yates Says:

    Glad to see that there’s some more modules hanging around where people are taking password hashing seriously. It’s nice to see someone actually think:

    * Salts … bloody good idea
    * Random salts … even better
    * Hashing using something a bit stronger than MD5 (not saying that MD5 isn’t good … just SHA512 is better)

    However there are a few points with your algorithm that you may want to consider in future versions (I apologise if there is anything that Rails does automagically that I’m mentioning here)

    * You’re only hashing the password once. Now even though SHA512 is a good hashing algorithm you may want to consider passing it through the algorithm a few more times. I think the RSA recommended amount is 1,000 times! Seems a bit excessive but as you’ve mentioned that this procedure is a very small amount of the entire lifetime of a user on a website so it’s not that bad to CPU load this section

    * There is no normalisation of user input. Imagine a situation where a user enters a password which contains a non-ASCII character on a Windows 2000 box & then attempts to re-login on a Linux box. There’s a risk that the encodings both OSs use could cause problems with byte representations & digesting. It would be worthwhile to ensure that you’re in UTF8 or some kind of universal character set

    * Some databases can have problems storing non-ASCII Strings (Oracle springs to mind). So before storage I’d encourage using BASE64 encoding of the byte digest and storing this instead.

    However the module is very good in its current state & something which really is a step in the right direction πŸ™‚

  2. Mikkel Riber Says:

    Hi.

    Love your password lib – it saved me for some headache.

    At the moment we are 2 developers working on a project, and i have a database with users and hashed passwords.

    Is it true that a hash string, generated on my server won’t work on his server? We entered the exact same password hash into his user db, but it wouldn’t authenticate – if we generated a new hash on his server everything worked fine.

    Best Regards
    Mikkel Riber

  3. de tomKronieken » Blog Archive » links for 2008-01-23 Says:

    […] Ruby on Rails Password Hashing Module Shared with shareomatic.com […]

  4. Gerrad Fase Says:

    Where can I download this library – is it an available Gem on RubyForge?

  5. Zachary Fox Says:

    I’ve updated this page so that you can download the password.rb file. Just look at the bottom of the source code for a link to download it.

  6. Gerrad Fase Says:

    Got it! Thanks a ton – now to put it to work.

  7. Thomas Says:

    A few points: Your code gave me a little headache, since it uses dots (.) where ruby expects quotes (‘ or “), but this was solved very fast.

    Second, in User.rb, the password will only be hashed, when the user is created. If you change the password, it just stores the plain password.

    So instead of using before_create you could just overwrite the assignment method:

    def password=(pass)

    write_attribute(:password, password = Password::update(pass))

    end

    Now the password will always be hashed.

    Best Regards
    Thomas

    P.S.: be sure to remove before_create, otherwise your password will be hashed twice and you cannot login.

  8. Thomas Says:

    I have to comment myself:

    the assignment-method works, but the cost is, you cannot validate the password (e.g. against a minimum length), because validations uses the hashed value of the password. A better approach is:

    protected
    def before_save
    self.password = Password::update(self.password) if self.password_changed?
    end

    But even here, you have to validate like this:

    def validate
    if self.password_changed?
    errors.add(“password”, “at least 10 characters”) if self.password.length < 10
    end
    end

    since all other validation-methods will use the hashed-version of the password, when you e.g. change some other attribute but not the password.

    Best regards
    Thomas

  9. Zachary Fox Says:

    @Thomas

    Good points. These are very simplified examples of code that is in a CMS I wrote. I actually use a before_save method to check the values of password and password_verification fields (which are submitted from a form), along with additional validations to ensure that the password is valid (length, complexity, etc…)

    For multiple reasons, I haven’t provided complete examples, but enough that you can work with the password.rb lib.

    I’m glad you found it useful, and I’ll look into the source files to see why the quotes aren’t working properly.

  10. fophillips Says:

    Is this code released under a specific license? I would like to use it in my project under the AGPL.

  11. Hugo Peixoto Says:

    @Thomas
    Instead of before_create, you could use after_validate_on_create.

  12. valley Says:

    In Password.salt what do i have to enter for salt = .. ?
    Whatever i take i get an error

    TypeError (can’t convert Fixnum into String):
    /lib/password.rb:33:in +'
    /lib/password.rb:33:in
    salt’
    /lib/password.rb:9:in `update’

    in Password.store, and the salt value is never 64 chars long.

  13. links for 2009-03-14 « Amy G. Dala Says:

    […] Ruby on Rails Password Hashing Module (tags: ruby rails security reference) […]

  14. Diego Soares Says:

    I got an error when I use variable salt as “salt = ..”, How can I solve it?

    Thanks,

    Diego

  15. Rajat Says:

    Thanks Zachary, very useful.

    In my Model, i added a validation to make sure PWs are being salted properly:
    Class User 192 #this is how long the salted hashed pws should be
    end

    its a handy error check. thanks again

  16. Rajat Says:

    seems like wordpress stripped out some stuff:

    validates_length_of :password, :is => 192 #this is how long the salted hashed pws should be

  17. Guy Says:

    Diego wrote: “I got an error when I use variable salt as β€œsalt = ..”, How can I solve it?”

    I just replaced that line with:
    salt = “”

  18. lzap Says:

    Theres a “bug” in your code. The get_salt method should be

    store[128..191]

    and not 192. But in Ruby this is not really a problem πŸ™‚

  19. Mr. Return Says:

    Typo: “psuedo-random”.