I had been a couple of days watching Inputs.io, the new design and the new password hashing.
Dealing with passwords is a very complex job, but here it goes my suggestion.
The main targets of this suggestion is that if someone can sniff the trafic (with HTTPS this is not possible) he cant see the password, the sha512 hash or the 2FA.
If the user has not enabled 2FA:
The login form:
- Email Input (type text)
- Password Input (type text)
- Server Token Input (type hidden)
- Client Token Input (type hidden)
When the user clicks Login Button:
- Using javascript and sha512.js, the email, the password, the server token and the client token are concatenated and hashed.
- Note: The Server token is a random string that the server provides in each petition (can be rand() or something).
- Note: The Client token is empty and the client browser fills it with a javascript random function on form submit.
So, your client hashes all the things (email, password, server token, client token), and sends to the server this values:
- Hash (the sha512 generated)
- Client Token (is generated by the browser using random function)
- Email (needed to find the user)
Summary:
If you sniff the conecction you only get a sha512 hash (that is different every login), the email and a Client Token that is just a random number.
You would have to sniff the Server response to get the server token and also the client response to complete the hash.
How the server validates the user:
if($_GET['hash'] == sha512($_GET['email'].$query['password'].$query['server_token'].$_GET['client_token']))
If the user has enabled 2FA:
The login form:
- Email Input (type text)
- Password Input (type text)
- Server Token Input (type hidden)
- 2FA Input (type text)
The same as above, replacing client token with 2FA code, as the 2FA code is not sended to the server (only the resulting sha512 hash) if someone sniffs the conection he would only get a random sha512 hash.
He would not get even the 2FA code.
//Also replace $query['2FA'] with the supposed 2FA for this user at this time
if($_GET['hash'] == sha512($_GET['email'].$query['password'].$query['server_token'].$query['2FA']))
Note: You can first hash the password and then concatenate to the other inputs and then hash again, this way the password goes also hashed.
Also you can also hash the email (in the database the email had to be in plain, but the user can send the email also hashed)