The majority of personalized web sites use some kind of form-based password authentication where you have two form fields for username and password, and a login button. When you submit your authentication, the password is sent to the server for verification against a user database.
This method has several security implications:
- The Password is transmitted unprotected.
This can be solved by transport-level encryption, but is vulnerable to in-the-middle attacks on networks with rogue DNS servers. - The Web Application has access to the password.
You'll just have to trust that the web site developer has employed proper data protection principles. Cross-side scripting attacks and other attacks might expose the password to an adversary. - The Password might be stored without adequate protection in the user database.
You as the user have no means to verify that the web site actually stores the password in a sufficiently secure form. This makes your password vulnerable to break-ins at the web site, and brute-force attacks.
Solution: Hash the password on the client side
By protecting the password on the client side, the clear text password never leaves the browser. This is simply done with an onSubmit JavaScript:<form onsubmit="pwField.value = b64_sha256(pwField.value);">
See a demonstration of how this works here.
This solution has several benefits:
- Password is always protected.
Since the hashing is performed before form is submitted, the password travels protected, and the web site sees only a hash of the password. - Password length and other password properties are hidden.
With the b64_sha256() function above, all password and passphrases are hashed to a 43-character string, regardless of password length. This hides the actual length of the password, and what characters or character set in use.
- Requires JavaScript enabled in the browser.
Some users disable JavaScript in their browser, or use a browser with a broken or incomplete JavaScript implementation. - Dictionary attacks on passwords slightly simpler.
Hashing algorithms can be much faster than other encryption algorithms that might be used to protect the password in the database. - Vulnerable to password sniffing
The hashed password is password-equivalent, i.e. it can be used to login just as the original password, and must be protected in transit with SSL.
I have tested the demonstration on Opera 8.5, Firefox 1.0, MS IE 6.0, Safari 2.0, and they all yield the same results.
Further improvements
This scheme can be further improved.Keying the hash with user ID
To protect against password equality tests and dictionary attacks, the hash can be keyed with the user id or some other data available within the same form:<form onsubmit="pwField.value = b64_hmac_sha256(userId.value, pwField.value);">
See a demonstration here.
This solution is still vulnerable to replay attacks, so the result must be submitted over a secure transport.
Challenge-response schemes
To protect against replay attacks, challenge-response schemes could be employed. In this scenario, the password hash is keyed with data generated by the server when it presents the login form. Upon submission, the server re-computes the hash based on the stored password information.To see a more detailed explanation of this, and an example, see Paul Johnston's description and proposed solution. Paul also has a description of a dream login system based on CHAP login schemes.
Paul's suggestion is based on the server generating a challenge when presenting the login form and storing these challenges to test their recency and validity. A simpler scheme could be to generate the challenges based on the date and time, reducing the resolution to yield a time slot for the challenge's validity.
In Perl, the challenge can be generated like this:
use Digest::SHA qw(hmac_sha256_base64);
print hmac_sha256_base64('Company Secret', time() >> 5);
Please choose a better key than Company Secret to generate your challenges...
Since the challenge is updated every 32 seconds, one might want to test against a number of generated challenges when performing the authentication, for instance like this:
use Digest::SHA qw(hmac_sha256_base64);
my $seed = time() >> 5;
foreach my $i (0..3) {
my $hash = hmac_sha256_base64($passwd_hash,
hmac_sha256_base64('Company Secret', $seed-$i));
if ($hash eq $q->param('password')) {
$ok = 1;
last;
}
}
A PHP implementation is of course also possible, but I didn't have a PHP installation with SHA-256 available.
See a demonstration here.
To further improve security several hashing keys could be used instead of the constant Company Secret suggested above
The hashing keys can be employed using a rotational scheme, or even generated randomly and stored in-memory in the servers.
Other issues
Some other areas also need attention to maintain the improved security of this scheme;- user sign-up,
- brute-force break-in attempts,
- compromised passwords, and
- initial password distribution.
- GnuPG or S/MIME encrypted e-mail to a verified e-mail address and pre-registered public key or certificate
- Text message to a mobile phone
- Certified mail
- Personal delivery
- Attempts against the same user from the same computer
- Attempts against multiple users from the same computer
- Attempts against multiple users from multiple computers
- Phishing attempts
- keying challenges with remote host and / or user id, and
- limiting the rate of challenges produced for a particular remote host or user name to for instance once per minute.




0 kommentarer:
Legg inn en kommentar