I just finished Hartl\'s Rails Tutorial book and I\'m using his account authentication logic in my first rails app. However, when I make a new user account and set it as an
try to change your before_save method:
def encrypt_password
if password.present?
self.salt = make_salt if new_record?
self.encrypted_password = encrypt(password)
end
end
UPD. or you can make it little shorter
def encrypt_password
self.salt = make_salt if new_record?
self.encrypted_password = encrypt(password) if password.present?
end
Not sure what is going on specifically. Could be that the password is getting encrypted again using a different salt (which is based on the time). Try adding debugger
to the first line of encrypt_password
and then run the same code from the console to see if the password is getting encrypted when you run toggle!
There's something odd going on in your code. A salt should be independent of the password, but your (Hartl's?) make_salt method says:
def make_salt
secure_hash("#{Time.now.utc}--#{password}")
end
This might have been the source of your nil
problem, since you were accessing password
inside make_salt
; in any case this is bad crypto since it amounts to using Time.now
as a "random" salt, which is much easier to crack (build rainbow tables for).
You should instead be using a good random number generator, e.g. Ruby's built-in SecureRandom
:
def make_salt
SecureRandom.hex(64)
end
Why such a long salt? According to https://crackstation.net/hashing-security.htm, "To make it impossible for an attacker to create a lookup table for every possible salt, the salt must be long. A good rule of thumb is to use a salt that is the same size as the output of the hash function. For example, the output of SHA256 is 256 bits (32 bytes), so the salt should be at least 32 random bytes." I don't want to use SecureRandom.random_bytes(32)
to avoid potential database string encoding problems with non-ascii characters, and 64 random hex characters comprise 32 random bytes, which I think counts as the same entropy.