hash - Is Blowfish necessary for security token in PHP remember me system?
I've search SO and I know there are a lot of “Remember Me” questions but I couldn't find one specifically about using Blowfish for generating security tokens.
I'm implementing a login system to use cookie-based “Remember Me” functionality and all the tutorials I've read either don't look secure (e.g. just an unsalted md5 hash based on the time) or look overly complicated.
I am not building sites for a bank or anything like that but just want a reasonable level of security.
The system I am proposing is to simply create a 128 char random string for the user name and a second 128 char string for a login token. The raw strings would be stored in a cookie and unsalted sha1'd versions would go in the row of their user account in the database.
I guess I could even regenerate the strings on every page load.
To me this offers decent security (I think!) because:
- A hacker can't target a specific account but knowing their user name (they would need to know the 128 char string)
- To forge the login cookie and gain access to the account someone would have to guess 2 x 128 char strings.
- If the database is hacked creating a rainbow table for 128 char strings is too difficult.
- I can safely remember the user name only with storing the actual user name in the cookie.
My questions are:
- Does this sounds reasonably secure? Should I be using strings longer than 128 chars?
- Is it worth using Blowfish instead of sha1? (I.e. am I right in saying the rainbow table is too difficult to produce?)
- If not, is there any advantage to running sha1 say 1,000 times?
Many thanks.
Answer
Solution:
Well, there are two things that blowfish can mean. The Cipher (two way encryption algorithm) or the Hash (one way hashing algorithm, specifically called bcrypt). But more on that in a bit.
So let's look at your assumed advantages.
A hacker can't target a specific account by knowing their user name.
Even if they knew the username, it wouldn't matter. The 128 bit random string is large enough that you really don't need to worry about an attacker guessing it. Let's do some math.
So unless you are concerned about an attacker trying to break into your system in the next trillion years, 128 bit is plenty strong enough...
To forge the login cookie ... would have to guess 2 x 128 char strings
We've already shown that guessing 1 is not going to happen. So adding a second is not necessary (it may not be bad, but it's not needed)
If the database is hacked creating a rainbow table for 128 char strings is too difficult
Yes. However that's not what you should be concerned about. What you should be concerned about is brute forcing. But more on that later...
So, to answer your actual questions:
Does this sound reasonably secure.
Reasonably, sure. Over-complicated: definitely. There are simpler ways of dealing with this...
Is it worth using Blowfish instead of sha1.
No. Blowfish is for derivations (meaning where you want a proof of work). In this case you want to generate a MAC (machine authentication code). So I wouldn't use either Blowfish or SHA1. I would use SHA256 or SHA512...
Is there an advantage to running sha1 1000 times.
No
The better way
The better approach that I recommend is to store the cookie with three parts.
Then, to validate:
Now, it's very important that the
SECRET_KEY
be a cryptographic secret (generated by something like/dev/random
and/or derived from a high-entropy input). Also,GenerateRandomToken()
needs to be a strong random source (mt_rand()
is not nearly strong enough. Use a library or mcrypt with DEV_URANDOM)...And timingSafeCompare is to prevent timing attacks. Something like this:
Answer
Solution:
As far as i can judge, the cruial point is, how you generate the random token, and what alphabet you allow in this string. Assuming that you use the random source of the operating system to generate this 128 character string, and allow case sensitive characters and digits, you get a very strong and unpredictable "password".
While my feeling tells me to use BCrypt (there is no reason against it), pure logic says that:
I would not use SHA-1 though, this reduces the entropy of your safe token to 160 bit. It doesn't make sense to create a super strong token, only to store part of it, instead use SHA-256 or SHA-512.
There are other things to consider, configure the cookie, so it can only be sent over HTTPS. Actually you will face the same problems as with maintaining a session.
Answer
Solution:
If you are using SSL to create a secure connection to exchange the tokens then I would say that this is fairly secure. I would just use something like a guid though for the token, not blowfish or SHA1. Those really don't get you anything, when what you really want is a large random string of bits.
If you aren't creating a secure connection in the first place then the man in the middle attack is likely and very easy to accomplish. Since SSL creates a random key each time, there really is no reason to change the token with each page load.