I’ve been thinking about the way normal login forms work. Normally a user is shown a login page, enters his username and password, submits the form, upon which the back-end of the code hashes the password, and see if a user exists with the given username and the hashed password. This works relatively well, but my problem with it is that when the user posts his credentials, they are submitted over the internet in plain text, making it very vulnerable to a Man in the middle attack (given the site is not using SSL).
So I thought about it some more, and came up with a scheme that I think prevents the man in the middle attack without the need for SSL.
The outline of this scheme is as follows:
- The user enters the login page. On the login page a random key is requested from the back-end, let’s call it secret_key. This is put in a hidden field on the login form. The back-end remembers the key it generated for the form in a session.
- The users fills in his username and password and submits the form
- Upon submit, a javascript function is fired that hashes the users password (using md5,sha1,any one-way hashing function really) concatenates it with secret_key, and hashes the concatenation again. So what you get is
key = hash(hash(password)+secret_key)
Then the javascript replaces the password field with as zeroes (as much zeroes as the user entered characters, as to not confuse him that the password appears to be changing).
Then the form is submitted.
4) The backend receives the username and the key, and can then request the record from the database with the given username, hash the password associated with that user, concatenate secret_key, which it also knows as it was the back-end that generated and stored it in a session in the first place, and then hash it again.
So, as the server already knows the hash of the password and secret_key, it can determine
key2 = hash(hashed-password-from-db + secret_key)
If key equals key2, the user entered the correct password and is logged in.
If this fails you would also need to check the normal way as described in the first paragraph of this post, for those who have javascript disabled.
As far as I can see there is no way for the man in the middle to repeat this request because secret_key changes every time the login page is shown, and he has now way of recovering the entered password from the key (given a strong enough one-way hashing function of course).
What do you think, would this method work? Are there any pitfalls?