One Password To Rule Them All

Most users rely upon a small number of passwords — often only one — that they use everywhere.

For their corporate domain account, their blog, their photo site, their email, their banking and PayPal accounts, and their discussion groups, one key opens them all. Despite the incredible risks involved with this practice, it is more prevalent than ever.

Password reuse is often a learned habit of jaded users who’ve been bitten by the “lost password” bug a few too many times, especially against sites that they seldom visit. Automated password management systems, such as those built into just about every browser now, help lubricate the usage of more secure passwords, but their single–PC implementations and data loss potential has many shying from trusting them.

It’s so much easier to remember one or two password derivatives than it is to remember dozens.

Of course, few will actually admit to recycling passwords like this, and instead it’s the guy using unique 20 character random sequences that are most likely to speak out. Impromptu prodding of acquaintances, clients, and contacts, along with the results of several recent security surveys, has me convinced that these security best-practice aficionados are the exception, and a large number of users, perhaps even a majority, are dangerously reusing the same password prolifically. Look at the outrage and fear when a site like Reddit loses their user’s plaintext passwords (it is hardly alone in having this happen). Of course the users could simply change their password, but the source of the outrage was because this was the one key for many of these users.

If someone discovers your password on site A, there’s a very good probability they can use it to access site B, and C, and D, and E, and so on (especially when your username is your email address). The security of your online reality relies upon faith in a lot of people who you shouldn’t have faith in. The weakest link can make it all unravel.

On sites that I’ve architected, I’ve tried to minimize the potential damage of a hypothetical exploit by eliminating the target surface area.

Following this philosophy, not only do I not want to store your password — of course I only store a hash and not your original password, which should be a universal practice even among “low value” sites — but I never want your probably-reused password ever hitting the site in the first place.

Instead of sending your password to be hashed on the server, I want it hashed on the client end, before it even gets sent down the wire.

This wouldn’t be a possibility without JavaScript, however the functionality of JavaScript has become pretty much mandatory, and is growingly becoming necessary for even the basic functionality of the site. As such, the account creation and logon system incorporates functionality that hashes a combination of your username, password, and the domain on the client end, passing through the hash to the server as your “password”. As a secondary benefit, the server can generate single-use variants (salts of sorts) which it provides with the form. If such a variant is provided, after the client script has created the hash, it then hashes the first hash with the variant, which the server can do as well, offering basic line encryption as well presuming that the server is tracking the variants, and ensuring they are server provided and not reused (it doesn’t replace SSL, and there are still avenues for man-in-the-middle attacks and untrusted remote servers masquerading as the official site if they overrode DNS, however it’s a step in the right direction where SSL can’t or won’t be used, which is the case for the vast majority of sites out there).

The SHA1 algorithm is easy to demonstrate (albeit also extremely easy to “crack” — it was built for speed — so don’t use it in practice), so in the example I used the excellent SHA1 implementation by Paul Johnston. Implementing it was trivial, and a simple example demonstrating how to use it for this purpose follows.

Note that this is purely an example, and in the wild you would want to use something much more computationally demanding, such as multi-rounds of blowfish. Something that makes brute force matching much more unreasonable.

<script language=”JavaScript”
src=”sha1.js” type=”text/javascript”></script>

<form
name=”loginForm” id=”loginForm”>
<input id=”passwordHash” type=”hidden” value=””>
Email Address: <input id=”emailAddress” type=”text”
size=”20″><br/>
Password: <input id=”password” type=”password”
size=”20″><br/>
<input type=button onclick=”DoLogon();” value=”Logon”
/>
<input type=hidden id=”variant” value=”” />
</form>
<script language=”JavaScript”>

function DoLogon()
{
var username =
document.getElementById(“emailAddress”).value;
var password =
document.getElementById(“password”).value;

var hashString = password + ‘|’ + username + ‘|’ + document.domain;

var hash = hex_sha1(hashString);

document.getElementById(“passwordHash”).value = hash;

/* Remove the password element from the form before
submitting */

document.getElementById(“loginForm”).removeChild(document.getElementById(“password”));
/* Submit the form. */
document.loginForm.submit();
}

Voila. Now I never know that you use the password 4muppet8 on every site, and instead I only ever see a unique hash specific for this domain. If you accidentally enter the login credentials for another site (this is a huge security risk that catches people frequently), my logs will never betray what it was. If someone mirrored this page on another site for spoofing purposes, and they weren’t smart enough to modify the javascript, even if the user entered their credentials for my site they still wouldn’t see it (because it is hashed against their domain. e.g. paypalspoof.com).

Of course this scheme still suffers a critical weakness: If, somehow, a nefarious agent could replace the server side scripts, and somehow my remote server validation scripts failed, they could simply alter it to pass through the original password. While that scenario is far more remote and unlikely than the already remote and unlikely database delving or line monitoring, it does demonstrate why the optimal situation would be intrinsic browser support: Instead of creating a site-specific custom script to secure and individualize the password for a specific domain, which allows users to reuse passwords without actually giving the password to any specific site, the browser should support this functionality directly, and it should be uniquely evident in the UI when such a secure password element is in use.

In addition to the password input type, there should be a secure password type (with obvious, non-spoofable graphical indicators that it is a secure password box) as a basic HTML element, automatically incorporating this sort of enhancement. HTTP already supports digest autentication, which is similar, but unfortunately it is incompatible with the form logon approach commonly used, not to mention that it has its own failings.