Monday, February 27 2006

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 easier to crack), 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);
 
  /* Variant - trivial "encryption" if the server has provided
     a tracked, single use pseudo-salt. */
  var variant = document.getElementById("variant").value;
  if (variant.length > 0)
  {
    hash = hex_sha1(hash + "|" + variant);
  }

  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.

   

Reader Comments

You might want to consider a distributed solution like OpenId.
christopher baus @ 2/27/2006 9:36:12 AM
The browser already has a solution to this issue, it is called "Digest Authentication" similar to "Basic Authentication" but instead of sending the password in the clear it sends a hash of the password.

The disadvantage is that it pops up the non-customizable browser dialog to get the login data.
Baruch @ 2/27/2006 12:44:29 PM
A good day to you Baruch.

Indeed, I mentioned digest authentication in the final paragraph, however as a technology it is virtually never used (I've never actually seen it in use in the wild) for many of the same reasons that Basic authentication isn't used.

(You likely saw an earlier revision through an aggregator, however I did add the digest auth comment several hours ago. Honest!)
Dennis Forbes @ 2/27/2006 1:06:39 PM
It is not impossible that I just skipped reading the last pararaph, I tend to read by skipping parts of articles. It makes for a faster reading, at the cost of losing some details :-)
Baruch @ 2/27/2006 1:19:44 PM
It does need to be built-in, but for now there are several bookmarklet-based solutions that hash the domain and a master password given by the user. Of course, this means never being able to access any account if you're on a new PC without first installing the bookmarklet.
Stephen Clay @ 3/20/2006 11:01:28 PM

Add Comment

Name *:

Email Address:

(your email address is not displayed)
Website:

Comment *:



About the Author
Dennis Forbes Dennis Forbes is a Toronto-based software architect. While focused primarily on the .NET and SQL Server worlds, Dennis frequently ventures outside of this comfort zone into game development and image processing. He has been published in several industry magazines, has been quoted in the Wall Street Journal and has been interviewed by NPR.

He is a vice president and lead software architect at an innovative New York City hedge fund back-office services firm.

Dennis has been working on solutions for the financial, telecommunications, and power generation markets for over 15 years.





 

Dennis Forbes