Most of the ideas in this section are hypothetical, although some have been implemented successfully. I would be interested to hear from people who try to implement anything on this page.
If JavaScipt is not available, the site has a choice - it can either allow a login with the password unencrypted, or block the login altogether. I recommend allowing unencrypted logins; sites that can't accept this risk should probably be using SSL. However, the site should warn the user that their password will be at risk.
To allow an unencrypted login, the server code to check a password needs to be updated. Calculate hex_hmac_md5(server salt, received password); if this matches the stored serve value, login is successful. To warn users of unencrypted logins, have a script block in the login form, with a noscript tag containing a phrase like "Warning: this login will not be encrypted".
Save Password Feature
For some web sites, including a dynamic challenge on every login form is not practical, for performance reasons. This is particularly true on sites that have the login form on every page. It is still possible to use challenge-response authentication on such sites, and avoid replay attacks; one approach is:
- Have the login form contain a static master challenge.
- The client sends (master challenge, secondary challenge, hash)
- The server checks the secondary challenge has not previously been used, and records it, to prevent replay attacks.
- Periodically, the master challenge is changed, and when this is done, the database of used secondary challenges can be cleared.
- Session ID is Unencrypted
- This can be strengthened, but doing so greatly increases complexity. As well as using a session cookie, each URL needs an individual authentication token. more...
- Replay Attacks
- If the application can save state on the server, this can be easily fixed. Instead of using a timestamp as the challenge, generate 128-bit random challenges, and keep track of issued challenges. When a login attempt is made, first check the challenge was issued by the server, and then remove it, so it can't be used again. The alternative login system also solves this. more...
- Active Interception
- There is no known way to protect against this, other that using SSL.
- Registration and Change Password
- Several ways to strengthen this have been suggested:
- The alternative login system solves this. more...
- Brute Force Attacks
- SRP prevents brute force attacks. For challenge-response, several approaches can be used to make brute force attacks harder, but not to stop them altogether:
- Avoid the challenge and response being transmitted together. This forces an attacker to capture the traffic in both directions, to conduct a brute force attack. However, this is of limited benefit, as in most sniffing attacks, traffic in both directions can be captured.
- Stored Password Equivalents
- Both SRP and the alternative login system solve this. more...
There is an alternative approach to challenge-response that resolves several risks, although it creates some new risks too. It is also based on a challenge, but the arrangement it different. When the server issues a challenge, it already knows md5(hmac_md5(password, challenge)). The client sends hmac_md5(password, challenge). The server performs an md5 on the value it receives, and if this matches the stored value, authentication is successful. This is secure, because to produce a value that hashes to the server's stored value, the password must be known.
Once a challenge has been used, we need to create a new one. To do this, the login form contains a next_challenge hidden field. md5(hmac_md5(password, next_challenge)) is sent to the server. To calculate the login hash, the client needs to know the challenge, which is different for each user. When the user name is entered, the client makes an Ajax call to fetch the user's challenge.
- Store the server secret in global application configuration. Note: unlike the server salt in the other system, server secret does need to be kept secret.
- Add a column to the user table to store the current challenge.
- Modify the login form:
- Add a hidden field "next_challenge" containing a randomly generated challenge.
- Add an empty hidden field "next_password".
- Add a script tag to link to
password.value = hex_hmac_md5(password.value, challenge.value);
next_password.value = hex_md5(hex_hmac_md5(password.value, next_challenge.value));
- Create the Ajax callback:
- Fetch the user's challenge.
- If the user doesn't exist, we don't want to reveal this. Instead, return hex_hmac_md5(server secret, user name).
- Modify the handler that receives posted login data:
- Calculate hex_md5(received_value)
- If this matches the stored hash, the login is successful.
- Update the stored password and challenge, with values received from the client.
- Update registration and change password:
- Add a hidden field containing a randomly generated challenge.
- Add a script tag to link to
password.value = hex_md5(hex_hmac_md5(password.value, challenge.value));
If you have an existing site. the main challenge is how passwords are stored in the database. If they are currently unencrypted, you can do a one-time operation to replace them with hashes. If the passwords are already hashed, you will need a complex migration process.
- Information Leakage
- However, related to this, an attacker can see when a user has logged in, because the random number changes on every successful login. The change in random number confirms to the attacker that the account does exist.
- Non-Standard Approach
- While this approach appears to me to be secure, it has not been subjected to anything like the degree of scrutiny that challenge-response login has.
- It is best to avoid saving the password on the client. Instead, a temporary password can be derived from the plaintext password, and the login challenge, and all tokens generated from this.
- To get the security benefits of this system, replay attacks must also be prevented. more...
This system is purely hypothetical at present. I advise against its use, as a site that requires this level of security should use SSL. However, I would be interested to hear from anyone who tries to implement this.