Page 1 of 1

Absolutely 100% safe login script?

Posted: Tue May 12, 2009 3:53 pm
by GimbaL
I need to write a login / user authentication script that's absolutely safe. Of course 100% is never possible, but I want to make sure not to have any known security holes.

My considerations so far:
- https only, http connections are refused or redirected to https
- the obvious anti injection measures, like escaping all strings in queries that come from user input or can possible be modified by users (like urls, cookies, post vars, session id's, etc)
- don't store passwords in database, only hashes of salt+peppered passwords (so no rainbow tables can be used and similar passwords cannot be detected)
- don't submit password from login form directly, but hash it with some time-limited random token (so somebody else submitted the same data later on will not be able to login, even if there's an https spoofing man in the middle)
- store some session flag upon successful login, which is checked in every page of the secured area, if it's missing, redirect to login

Am I on the right track?

I am breaking my head on the hashing / salting / random token part. How can I hash the password with some time dependent token on one end (login form), and with a salt+pepper on the other end (database), and still compare them?

About which kind of hash to use: with the recent progress on breaking MD5 and SHA1, I assume SHA512 is the best choice?

Re: Absolutely 100% safe login script?

Posted: Tue May 12, 2009 4:32 pm
by jayshields
You list most of the important points to a login script so I think your best bet is to have a go and post what you achieve - maybe even a live sandbox. More people will get involved and give you pointers then.

Re: Absolutely 100% safe login script?

Posted: Tue May 12, 2009 6:02 pm
by GimbaL
I have some difficulties that prevent me from beginning...

For example, the passwords in the database are stored like hash(password+A) where A is the salt. If I want the login script to also hash the entered password before transmitting it (I guess with JavaScript), it means I *must* use salt A there as well, otherwise I will never be able to compare them. Isn't it a security breach if my salt data A is publicly visible at the client side?

And what about the pepper (different salt for each user). I can not know in advance which pepper to use at client side, because I don't know which user is going to log in. I can hash in two steps: in the database I store hash(hash(password+salt)+pepper) (and also store the pepper string separately), and the form sends hash(password+salt), then then how do I verify the password? I cannot do "select * from users where SHA512(submitted_password+pepper)=stored_password" because MySQL does not support SHA512..?
The the only way I can think of is selecting *all* password hashes from the database. And do the SHA512 hashing + comparing them all in PHP. But that seems stupid, and besides isn't that a security risk too (especially when the database connection is not local)?

Re: Absolutely 100% safe login script?

Posted: Wed May 13, 2009 5:55 am
by jayshields
You're overcomplicating things.

- Don't do anything with passwords prior to transmission (at the client side) - HTTPS will encrypt this.
- PHP can hash things using SHA.
- For peppers you can use any arbitary user data such as date joined.

I can see what you're saying about MySQLs inability to natively SHA512 stuff - if that's actually the case, and the connection to your external MySQL server is not encrypted, then you'll have to fetch all hashed passwords and iterate them in PHP for retrieval, and do the hashing in PHP before the transmission - this way nothing is sent in plain text.

Re: Absolutely 100% safe login script?

Posted: Wed May 13, 2009 7:52 am
by kaisellgren
It is good to see you have taken security seriously. The approaches you are going to take (or you have taken) are good. However, this
GimbaL wrote:- don't submit password from login form directly, but hash it with some time-limited random token (so somebody else submitted the same data later on will not be able to login, even if there's an https spoofing man in the middle)
Is useless, because you are operating under HTTPS. Just send the credentials as is since the whole request will be encrypted anyway.
GimbaL wrote:I am breaking my head on the hashing / salting / random token part. How can I hash the password with some time dependent token on one end (login form), and with a salt+pepper on the other end (database), and still compare them?
Read above, you do not need to.
GimbaL wrote:About which kind of hash to use: with the recent progress on breaking MD5 and SHA1, I assume SHA512 is the best choice?
Being "the best" is a point of view. Fastest? Strongest? Most secure? If you use SHA-512, do not worry about its security (at least for a long time I hope).

If you want to have a salted challenge-response authentication, read more: http://tools.ietf.org/html/draft-newman-auth-scram-07

Re: Absolutely 100% safe login script?

Posted: Thu May 14, 2009 4:19 am
by GimbaL
Thanks for your replies.
jayshields wrote:- Don't do anything with passwords prior to transmission (at the client side) - HTTPS will encrypt this.
kaisellgren wrote:Is useless, because you are operating under HTTPS. Just send the credentials as is since the whole request will be encrypted anyway.
What about a possible man-in-the-middle attack? The recent SSL certificate checksums being forged, especially in combination with a possible spoofed DNS, makes me a bit paranoia.
kaisellgren wrote:Being "the best" is a point of view. Fastest? Strongest? Most secure? If you use SHA-512, do not worry about its security (at least for a long time I hope).
In this case that would be strongest / most secure (what's the difference?) so I guess SHA512 is best for me.
If you want to have a salted challenge-response authentication, read more: http://tools.ietf.org/html/draft-newman-auth-scram-07
Thanks... Not to be lazy, but is it possible to explain the idea behind this in a few lines? This document looks very formal, and I'm not sure if I get the big picture.

Since you suggest not to do any hashing client side (just send the raw password over https) it means I must do all the hashing, salting and challenging in PHP. How can I still get a randomized challenge? (or do I totally misunderstand the idea?)

Re: Absolutely 100% safe login script?

Posted: Thu May 14, 2009 6:36 am
by kaisellgren
GimbaL wrote:What about a possible man-in-the-middle attack? The recent SSL certificate checksums being forged, especially in combination with a possible spoofed DNS, makes me a bit paranoia.
That is something you can stop worrying about.
GimbaL wrote:In this case that would be strongest / most secure (what's the difference?) so I guess SHA512 is best for me.
I suggest you to use either SHA-256, SHA-512 or Whirlpool. The first produces a 256-bit output and the rest produce 512-bit output. Yes, SHA-512 is a good choice.
GimbaL wrote:Thanks... Not to be lazy, but is it possible to explain the idea behind this in a few lines? This document looks very formal, and I'm not sure if I get the big picture.
It requires that you expose your salt. That is not a problem as long as the hash value itself is safe, but like I said earlier, if you use HTTPS for your site, you do not need this.
GimbaL wrote:Since you suggest not to do any hashing client side (just send the raw password over https) it means I must do all the hashing, salting and challenging in PHP. How can I still get a randomized challenge? (or do I totally misunderstand the idea?)
Most applications do hashing on the server-side. I am not sure what you are referring to with that "challenging in PHP". If you use a secret key on the filesystem that you add into the hash then you must hash on the server-side (and you cannot use Challenge-Response).

Re: Absolutely 100% safe login script?

Posted: Fri May 15, 2009 5:57 pm
by leonel.machava
Hi GimbaL.
Hi Kai (congratulations for your Triton CMS project).

I am glad to know you are conscious about security.

I am developing a PHP framework/CMS and I implement registration/authentication in this way:

Registration process:
(1) The client sends username, password, etc, via HTTPS.

(2) I generate a random salt and I use it to hash the client password. This is the code:

Code: Select all

function hash_password($clear_pass,$salt = NULL) {
  if( !isset($salt) ) {
    $salt = md5(uniqid(rand(),TRUE));
  }
  return $salt . md5($clear_pass);
}
(3) Store all client data (name, hashed password, etc) in a database.

Login process:
(1) The client sends credentials via HTTPS.

(2) I search a user with the supplied name in the database. If the user exists I get its stored hashed password. I use the code given bellow to check if the client password is correct.

Code: Select all

// This function checks if a clean pass corresponds to an hashed pass.
function check_pass($clean_pass,$hashed_pass) {
  // Get the salt from the hashed pass (first 32 character).
  $salt = substr($hashed_pass,32);
 
  $test_hash = hash_password($clean_pass,$salt);
  return $test_hash == $hashed_pass;
}
 
Some notes:
a) When you send data via HTTPS you don't have to worry about a man-in-the-middle or replay attack. TLS/SSL does client/server authentication and encryption. It means that only your server will get and understand the user submitted data.

b) You don't need to do anything on the client-side. The browser does the work for you (all the TLS/SSL things).

c) I generate a random salt with this algorithm:

Code: Select all

$salt = md5(uniqid(rand(),TRUE);
. The salt is composed of 32 hex chars.

d) I used the MD5 algorithm but I recommend a stronger algorithm like SHA512. For using SHA512 with PHP, see http://www.php.net/manual/en/function.hash.php .

e) Even if an hacker gets access to the hashed passwords it is very (very) difficult to him to decrypt the password with brute force. Even knowing that the first 32 characters are the salt.

Besides a strong authentication, beware of:
  • SQL Injection
  • Cross Site Scripting (XSS)
  • Cross Site Request Forgery
  • Session hijacking
  • And others
The secret I guess you know: user input sanitization.

Cheers,
Leonel Machava

Re: Absolutely 100% safe login script?

Posted: Sat May 16, 2009 5:54 am
by kaisellgren
leonel.machava wrote:Hi Kai (congratulations for your Triton CMS project).
Eh, well, thanks, but it's almost 2 years old and I made it when I was starting with PHP...
leonel.machava wrote:(2) I generate a random salt and I use it to hash the client password. This is the code:

Code: Select all

function hash_password($clear_pass,$salt = NULL) {
  if( !isset($salt) ) {
    $salt = md5(uniqid(rand(),TRUE));
  }
  return $salt . md5($clear_pass);
}
The way you generate salt is weak and so is your hash algorithm.

Also, just a thought: wouldn't it be better to store the salt in a separate column? This way you are not wasting the column space for Salt+Hash, but for each separately. I mean, if you use VARCHAR, for instance, for your hash value column, then you may not be able to use more than 255 bytes for the column and your salt would eat 32 bytes itself already (if not more in the future).
leonel.machava wrote:It means that only your server will get and understand the user submitted data.
Not exactly true. Anyone else in between the server and the client or even "near" these nodes (eavesdropper) can get the user and the server submitted data. However, the data is encrypted and therefore useless.
leonel.machava wrote:d) I used the MD5 algorithm but I recommend a stronger algorithm like SHA512. For using SHA512 with PHP, see http://www.php.net/manual/en/function.hash.php .
Actually, if you are hashing your salt then SHA-512 is not likely to be any better than MD5 and in fact, you could just drop off that hashing from your salts. In case of password hashing, SHA-512 would be way more secure choice.
leonel.machava wrote:e) Even if an hacker gets access to the hashed passwords it is very (very) difficult to him to decrypt the password with brute force. Even knowing that the first 32 characters are the salt.
The salt prevents attacks, which utilize rainbow tables since the use of a 32-byte salt equals to Very large precalculated table. Salting does not help in case of brute forcing or dictionary attacks as the salt is known by the attacker.
leonel.machava wrote:Besides a strong authentication, beware of:
And others
The Others :)