I have an existing web application with a few thousand users which I'm porting over to Rails. As I rewrite and refactor this app I may need to run it on any number of different servers for development, testing, and production purposes.
I'm using Rails' built-in has_secure_password method in my user model but I'm concerned about the portability of password data. I will need to move the contents of my database from machine to machine to test in different environments and its very important that I can test the user authentication functionality using the same set of users and passwords in each environment.
So far its easy to find answers about how bcrypt-ruby works along with Rails has_secure_password
but after weeks of searching I haven't found a clear answer.
If has_secure_password
results in a WorkFactor + Salt + HashedPassword concatenated and saved to the password_digest
database column then can that hash be regenerated and compared reliably if moved to any other machine (assuming any other machine is running Rails on a Unix-like OS)?
OR To put it another way - are bcrypt-ruby passwords generated with Rails' has_secure_password
portable?
Follow up question: If the salt is always generated randomly (I've seen the same password use different hashes so I don't think the salt is created from the text of the password itself) then how would a Rails app be able to reliably rehash the password on a login form submit and compare it to what's in the database. Obviously it would have to know what the salt is first in order to compare it. How does it do that?
Yes the passwords are portable. The format used is a standard "crypt encoding" format, also used as part of RFC 2307 (in RFC 2307, the string would be prefixed "{CRYPT}"). I have worked with a Perl library Authen::Passphrase
that would happily authenticate passwords against the bcrypt-hashed versions from an RoR database.
For the follow-up question: The salt is embedded in the stored value (along with the type of hashing, the number of bcrypt cycles to use and of course the hash itself), and to authenticate the server needs to read the stored value, then it simply re-uses the same salt to generate the hash part - if the input password is correct, then the hash will be identical. The authentication process does not create a new random salt. A random salt is only created when generating a brand new hash for storing.
The bcrypt password is easily split into components for a server to read (I have chosen non-realistic characters to make it easier to see boundaries, in fact salt and hash are base 64 encoded binary data):
$2a$10$AaBbCcDdEeFfGgHhIiJjKk0987654321098765432109876543210
This part means "use bcrypt, 2**10 == 1024 iterations": $2a$10$
This part is the salt: AaBbCcDdEeFfGgHhIiJjKk
, always 22 characters
This part is the hash: 0987654321098765432109876543210
, always 31 characters
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With