Is Blowfish necessary for a security token in PHP, remember the system?

I have a SO search and I know that there are many Remember Me questions, but I could not find them specifically for using Blowfish to create security tokens.

I am implementing a login system to use the cookie-based Remember Me functionality, and all the tutorials I read either don’t look safe (like just a failed time-based hash MD5) or look overly complex.

I do not create sites for the bank or something like that, but just want a reasonable level of security.

The system I suggest is to simply create a 128 char random string for the username and a second 128 char string for the login token. Raw strings will be stored in a cookie, and unsaved versions of sha1'd will be in the string of their user account in the database.

I think I could even restore the lines every time the page loads.

For me, this provides decent security (I think!), Because:

  • A hacker cannot target a specific account, but knowing her username (they need to know the string 128 char)
  • To fake the login cookie and access the account, someone will have to guess 2 lines x 128 char.
  • If the database is hacked, creating a rainbow table for 128 char rows is too complicated.
  • I can safely remember a username only by storing the actual username in a cookie.

My questions:

  • Does this sound safe enough? Should I use strings longer than 128 characters?
  • Should I use Blowfish instead of sha1? (I. Am I rightly saying that a rainbow table is too difficult to produce?)
  • If not, are there any advantages to running sha1 say 1000 times?

Thank you very much.

+4
source share
3 answers

Well, there are two things that blowfish can mean. Cipher (two-way encryption algorithm) or Hash (one-way hashing algorithm, specially called bcrypt). But a little about that.

So let's look at your perceived benefits.

  • A hacker cannot target a specific account knowing its username.

    Even if they knew the username, it would not matter. The 128-bit random string is large enough, and you really don't need to worry about the attacker guessing it. Let's do some math.

    2^128 == 3 * 10^38 possible combinations Assuming there are 50 million servers on the internet, And each server can do 100,000,000,000 guesses per second (to your server) 3e38 / 50,000,000 / 100,000,000,000 == 6 * 10^19 seconds Which when converted to years is: 1,902,587,519,025 To have a 50% chance of guessing it, the attacker would need to hit 1/2: Years to 50% chance of guessing: 951,293,759,512 

    So, if you are not worried that the attacker is trying to penetrate your system in the next trillion years, 128 bits is a lot strong enough ...

  • To fake the login cookie ... you had to guess 2 x 128 char strings

    We have already shown that guessing 1 will not happen. Therefore, adding a second one is not required (this may not be bad, but it is not necessary)

  • If the database is hacked, creating a rainbow table for 128 char rows is too complicated

    Yes. However, this is not something you should worry about. What bothers you is cruel coercion. But more on that later ...

So, to answer your current questions:

  • Does that sound reasonable.

    Reasonable, of course. Complex: definitely. There are simpler ways to deal with this ...

  • Should I use Blowfish instead of sha1.

    No. Blowfish is for derivations (which means you want proof of work). In this case, you want to generate a MAC (machine authentication code). Therefore, I would not use either Blowfish or SHA1. I would use SHA256 or SHA512 ...

  • Is there any advantage in working sha1 1000 times.

    No

The best way

The best approach I recommend is to save a three-part cookie.

 function onLogin($user) { $token = GenerateRandomToken(); // generate a token, should be 128 - 256 bit storeTokenForUser($user, $token); $cookie = $user . ':' . $token; $mac = hash_hmac('sha256', $cookie, SECRET_KEY); $cookie .= ':' . $mac; setcookie('rememberme', $cookie); } 

Then to check:

 function rememberMe() { $cookie = isset($COOKIE['rememberme']) ? $COOKIE['rememberme'] : ''; if ($cookie) { list ($user, $token, $mac) = explode(':', $cookie); if ($mac !== hash_hmac('sha256', $user . ':' . $token, SECRET_KEY)) { return false; } $usertoken = fetchTokenByUserName($user); if (timingSafeCompare($usertoken, $token)) { logUserIn($user); } } } 

Now it is very important that SECRET_KEY be a cryptographic secret (generated by something like /dev/random and / or derived from a high entropy input). In addition, GenerateRandomToken() must be a strong random source ( mt_rand() not strong enough. Use a library or mcrypt with DEV_URANDOM) ...

And timingSafeCompare - prevent synchronization attacks . Something like that:

 /** * A timing safe equals comparison * * To prevent leaking length information, it is important * that user input is always used as the second parameter. * * @param string $safe The internal (safe) value to be checked * @param string $user The user submitted (unsafe) value * * @return boolean True if the two strings are identical. */ function timingSafeCompare($safe, $user) { // Prevent issues if string length is 0 $safe .= chr(0); $user .= chr(0); $safeLen = strlen($safe); $userLen = strlen($user); // Set the result to the difference between the lengths $result = $safeLen - $userLen; // Note that we ALWAYS iterate over the user-supplied length // This is to prevent leaking length information for ($i = 0; $i < $userLen; $i++) { // Using % here is a trick to prevent notices // It safe, since if the lengths are different // $result is already non-0 $result |= (ord($safe[$i % $safeLen]) ^ ord($user[$i])); } // They are only identical strings if $result is exactly 0... return $result === 0; } 
+7
source

As far as I can tell, the cruising point is how you generate a random token and which alphabet you allow on this line. Assuming you use a random operating system source to generate this 128-character string and are case-sensitive, you get a very strong and unpredictable "password".

While my feeling tells me to use BCrypt (there is no reason against this), pure logic says that:

  • 128 characters is much longer than regular salty passwords, so salting is not required.
  • It is not possible to combine the combination 62 ^ 128 = 2E229. Vocabulary aspects cannot be called either due to the random nature of the token. This means that iteration of the hash function is not required.

I would not use SHA-1, but it reduces the entropy of your secure token to 160 bits. It makes no sense to create a super strong token, only to store part of it, use SHA-256 or SHA-512 instead.

There are other things to consider when setting up a cookie, so it can only be sent via HTTPS. In fact, you will encounter the same problems as when servicing a session.

+1
source

If you use SSL to create a secure connection for exchanging tokens, I would say that it is quite secure. I would just use something like guid, although for a token, not for blowfish or SHA1. Those really get nothing when what you really want is a big random string of bits.

If you do not create a secure connection, first of all, a person in an average attack is likely and very easy to perform. Since SSL creates a random key every time, there really is no reason to change the token every time the page loads.

0
source

Source: https://habr.com/ru/post/1487305/


All Articles