Javascript and Security

Tweet

Dori Smith has a great entry on her Javascript Weblog about using Javascript to secure pages of her site. She argues that Javascript really isn’t the right tool for the job, and I completely agree with her. However, it is possible to yse Javascript to further improve the security of a server-side login system.

Unless you are using SSL, the chances are your site’s login system sends passwords in the clear. They may be embedded in a POST request but they are still fair game to sniffer programs such as Ettercap. While far from solving the problem entirely, you can reduce the impact of sniffing attacks by using Javascript to encrypt the user’s password before it is transmitted to your application. An evesdropper may be able to access your application using the data they have sniffed, but they won’t be able to access other applications that use the same password (most people use the same password all over the place).

But surely if the encryption is carried out by Javascript an attacker would be able to reverse engineer it and decrypt the password themselves? Not at all, thanks to the magic of one-way encryption algorithms – in particular, MD5.

MD5 is a one-way hashing algorithm. You give it an input, and it spits out an output. The trick is that there is no systematic way of retrieving the original input from the output aside from a brute-force attack. Javascript does not provide native support for MD5, but this free library provides an MD5 Javascript implementation specifically designed for preventing passwords from being transmitted in the clear.

Here’s a simplified explanation of how it works:

  • The web server serves up a form with a hidden field containing a random “challenge” string, and optionally a timestamp for when the form was served.
  • The user enters their password and submits the form.
  • Javascript glues their password on to the challenge and MD5 hashes them both. Only the hash is sent back to the server.
  • The server knows the user’s password and the challenge that was sent, so it hashes them and compares the result with the data sent by the user.

Naturally, when implementing such a thing it’s essential that the system functions even with Javascript disabled. You can do that by setting a variable in a hidden form field when the Javascript encryption method is used; the server can check if that field has been set and assume that the password was sent in the clear if it hasn’t.

If your web application stores encrypted passwords (as a well behaved application should) this technique can still be used – you just have to MD5 the password twice on the client side, once to get the encrypted version and then once with the encrypted version appended to the challenge to get the response which should be sent to the web server.

Example server side code for this technique can be found on this page of the Javascript MD5 site.

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

  • http://www.sitepoint.com/ mmj

    HTTP Digest Authentication does the same sort of thing. However, neither this solution nor digest authentication can protect against situations where a sniffer can “listen to” and “intercept” a connection between the browser and the server. Armed with a hashed password, it is still possible for a third party to gain access. The trick is to act quickly enough that the hashed password and challenge do not expire.

  • cyngon

    Perhaps you could reduce the possiblity for interception by checking that the IP address and user agent of the client before login matches those pieces of information after login. (?)

  • http://www.health.auckland.ac.nz hadley

    Does that actually help? The sniffer won’t be able to recover the original password, but can’t they just send the encrypted password?

    Obviously, it will be a bit more of a hassle as they won’t just be able to type the password into the form, but if they’ve managed to get a sniffer between you and the server…

    Hadley

  • http://simon.incutio.com/ Skunk

    Like I said in the original entry:

    While far from solving the problem entirely, you can reduce the impact of sniffing attacks by using Javascript to encrypt the user’s password before it is transmitted to your application. An evesdropper may be able to access your application using the data they have sniffed, but they won’t be able to access other applications that use the same password (most people use the same password all over the place).

    An evesdropping attacker can still access your application, but they won’t be able to use the password they’ve sniffed to access other applications as well. Additionally, with clever use of a timestamp on the challenge you can ensure they’ll only be able to access the application once for every time they sniff the authentication information. If you set it up so that the user’s password can’t be changed without them entering their original password again (a sensible security measure to take in any case) the attacker will be limited to the amount of damage they can do in the one session they have stolen.

    That said, if they’ve sniffed it once they’re likely to be able to sniff it again. For real security you should be using HTTPS; this solution is for when the economics of getting HTTPS set up aren’t realistic for what you are working on. Security is all about trade-offs after all.

  • http://www.rideontwo.com z0s0

    Somewhat on the topic – I must say the prospect of people sniffing packets isn’t something I lose sleep over.

    I’ve never heard of an actual case – for example – of credit card information being intercepted “over the wire” so to speak. It’s a very, very difficult thing to do. Can anyone cite some real life past examples?

    Even in local networks these days, switches rather than hubs are prevalent. If I, the network admin, wanted to sniff data I could certainly do it at the border router. But then I could far more easily install a key logger on my victim’s PC.

    To be honest I feel that, while we all use SSL for sensitive information, it is largely a placebo. Information is invariably compromised once it reaches its destination, and is aggregated with a lot of other sensitive data, rather than while in transit.

    A single piece of data alone is rarely worth the effort when the challenges of interception are so great.

  • Sher

    From some of the context of the blog, it sounds as if there is a point being missed here. The idea of the “challenge” is to make it a randomly generated variable which is sent out only once, encrypt it along with the password response into a single hash and, submit back to the server. It is at this point that the listener could intercept the hash. However, since the variable and password are hashed together and the server only sends the random number once AND the server has already recieved the authorized hash at this point (nullifying reuse of the random variable), any further attempts to resend the same hash would result in authentication failure. Pretty clever, IMO.