I am trying to figure out what would be the 'perfect' authentication system for a website.
On one end, we know that simple hashing algorithms can be brute-forced or cracked in other ways. Hence why MD5 is no longer recommended. The best solution for secure password storage, it seems, is making use of key stretching in combination with salting (i.e. using PBKDCF2, bcrypt or scrypt). For those who haven't heard of it, key stretching implies that a hashing algorithm will be computed through many iterations (not just once), causing each brute force attempt to take an unreasonable amount of time to compute.
Now, having users sign up, authenticate or change their password, and having the server use key stretching to store the password does ensure proper password protection -- but leaves the door open for DoS attacks. Mainly, a hacker could just flood it with authentication attempts with random passwords, and the server would choke on computing all those iterations for all those attempts.
I'm trying to get the best of both worlds -- secure password storage with key stretching, without the DoS door opened. Here's my idea, and I want to know if I'm overseeing anything, or if there's any problem in my logic... sometimes, when you're too close to the problem...
The idea is:
CLIENT-SIDE: Website user inputs username, password
CLIENT-SIDE: Website uses AJAX request to the server to retrieve the salt and number of iterations attached with the user's record (based on username match)
CLIENT-SIDE: Authentication Step 1. Website computes, on the client's computer with Javascript, all the hashing iterations MINUS ONE (I will explain why later). The computation is performed using a well-known algorithm, such as PBKDF2, bcrypt, or scrypt. Website sends the result to server.
SERVER-SIDE: Authentication Step 2. Server receives the username + hashed password (minus one iteration). Performs last iteration (with PBKDF2, bcrypt or scrypt) Compares with stored value to determine if combination is correct. Returns response to website.
Now, why all iterations minus one? If a hacker gets a copy of the database, and the server would expect a fully-hashed password to be provided, it would be equivalent to storing the passwords in plain text. Hacker would copy and paste the hash and use the authentication service. As such, we can't return it directly.
However, since we theoretically can't 'reverse' hashing, having the server only accept a n-1 iterated hash means the hacker can't guess what the previous iteration looked like, based on what we see in the database. Is that correct?
In the end, we have the majority of the work performed on the client-side (server only does one iteration), eliminating the DoS threat, but we also have passwords stored with full-on key-stretching with salt, a most secure practice.
Am I missing anything? Would this be an ideal way to implement an authentication system? Let me know! I'm just wondering if I'm missing anything here...