Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

Relevant XKCD

There are many sites on the Internet that require login information, and the only way to protect against password reusing is the "promise" that the passwords are hashed on the server, which is not always true.

So I wonder, how hard is to make a webpage that hashes passwords in the client computer (with Javascript), before sending them to the server, where they would be re-hashed? In theory this doesn't give any extra security, but in practice this can be used to protect against "rogue sites" that don't hash your password in the server.

share|improve this question
7  
a hashed password sent in the clear is no better than a password sent in the clear if the server is just comparing hashes, man in the middle attacks love this kind of "security" –  Jarrod Roberson May 17 '11 at 21:14
    
The best solution is (imo) a client side password manager. That way, you can generate a random string of characters as your password and you're not relying on the server to 'protect' you. –  Dean Harding May 17 '11 at 22:20
1  
@Jarrod - it sounds to me, though, like different web sites using different client-side hashing algorithms would prevent the attack described by that comic. One widely re-used password becomes many different passwords through those differing hash algorithms. That client-side hash calculation doesn't prevent other kinds of security being applied - such as sending the hash through a secure connection. –  Steve314 May 17 '11 at 22:26
    
One thing, though - why would a rogue site add javascript client-side password-hashing code that would prevent them from harvesting those passwords? Asking the black hats to block their own exploits seems, hmmm, what's the polite word... Anyway, as a standard browser security feature, it makes some sense to (non-expert) me. But not in javascript. –  Steve314 May 17 '11 at 23:10
2  
It sounds like your plan for protecting yourself against rogue sites is to ask the rogue sites to set up better security. ? –  pc1oad1etter Mar 9 '12 at 16:15
show 3 more comments

8 Answers 8

up vote 13 down vote accepted

I don't know why so many sites don't do it, but I know that it is possible and works well since I have done it already. The server sends a random salt string in the login page which gets appended to the password in javascript in the browser and the SHA1 hash of the result gets then submitted back to the server for verification.

Here is my SHA1 implementation in javascript, that you may use if you like:

function sha1(msg)
{
  function rotl(n,s) { return n<<s|n>>>32-s; };
  function tohex(i) { for(var h="", s=28;;s-=4) { h+=(i>>>s&0xf).toString(16); if(!s) return h; } };
  var H0=0x67452301, H1=0xEFCDAB89, H2=0x98BADCFE, H3=0x10325476, H4=0xC3D2E1F0, M=0x0ffffffff; 
  var i, t, W=new Array(80), ml=msg.length, wa=new Array();
  msg += fcc(0x80);
  while(msg.length%4) msg+=fcc(0);
  for(i=0;i<msg.length;i+=4) wa.push(msg.cca(i)<<24|msg.cca(i+1)<<16|msg.cca(i+2)<<8|msg.cca(i+3));
  while(wa.length%16!=14) wa.push(0);
  wa.push(ml>>>29),wa.push((ml<<3)&M);
  for( var bo=0;bo<wa.length;bo+=16 ) {
    for(i=0;i<16;i++) W[i]=wa[bo+i];
    for(i=16;i<=79;i++) W[i]=rotl(W[i-3]^W[i-8]^W[i-14]^W[i-16],1);
    var A=H0, B=H1, C=H2, D=H3, E=H4;
    for(i=0 ;i<=19;i++) t=(rotl(A,5)+(B&C|~B&D)+E+W[i]+0x5A827999)&M, E=D, D=C, C=rotl(B,30), B=A, A=t;
    for(i=20;i<=39;i++) t=(rotl(A,5)+(B^C^D)+E+W[i]+0x6ED9EBA1)&M, E=D, D=C, C=rotl(B,30), B=A, A=t;
    for(i=40;i<=59;i++) t=(rotl(A,5)+(B&C|B&D|C&D)+E+W[i]+0x8F1BBCDC)&M, E=D, D=C, C=rotl(B,30), B=A, A=t;
    for(i=60;i<=79;i++) t=(rotl(A,5)+(B^C^D)+E+W[i]+0xCA62C1D6)&M, E=D, D=C, C=rotl(B,30), B=A, A=t;
    H0=H0+A&M;H1=H1+B&M;H2=H2+C&M;H3=H3+D&M;H4=H4+E&M;
  }
  return tohex(H0)+tohex(H1)+tohex(H2)+tohex(H3)+tohex(H4);
}

This way you can of course also avoid to ever send the passwords over the net, even when the user chooses or changes his/her password: A random salt gets appended to the newly entered password in the browser and the hash of this gets transmitted to the server. If the password change is accepted the server needs to store the salt and the hash for the user account instead of the plain text password. The login page now uses two salts: the static one of the user account and a random one that is only valid for a single login attempt. The plain text password gets first hashed with the static user account salt and this hash is hashed again with the current login salt and this gets transmitted to the server.

Update: The response to this and other answers to this question shows that some further explanation might be helpful here:

What are the benefits of the suggested approach?

  • It is meant to make it considerably harder to harvest passwords from the data that is transferred over the network, i.e. by using a sniffer. It does not make it impossible to obtain a weak password from the data that gets transferred but strong passwords are save against all attacks that are feasible today.
  • It is easy to implement and requires no extra effort from the user, needs no special equipment on the users side and works with all browsers that support javascript. The users get a login page as they know it and as it is widely accepted.
  • The clear text passwords never enter the web server which makes it much harder to obtain them in case the server or it's database gets compromised some day.
  • It protects the passwords of all users of the website, whether they are aware of the problem or not.

How can it be attacked?

  • It can of course be broken if the attacker is able to manipulate the the website and/or the javascript that is transferred to the user. The attacker can then simply remove the hashing to let the browser send the password in clear text and may do the hashing himself if he still wants to send the response back to the origin server. But if this happens much more is at stake then just the protection of reused passwords. I.e. the attacker can then as well spoof the entire website. One possible protection against this attack would be to use a secure transport protocol like SSL. While this would make the first 2 benefits obsolete since they can now be achieved already by the transport layer security it would still have the benefit that the plain text passwords never enter the web server.

Why is it secure

  • The suggested approach uses a SHA1 cryptographic hash function together with a salt. While the SHA1 hash function is considered relatively weak (in theory) compared to hash functions that use more bits it is still entirely save against preimage attacks which would be required to obtain a unknown strong password from the data that gets transferred. There has been not a single successful preimage attack reported against SHA1 to this day on any hardware, not even against MD5 which is considered to be weaker then SHA1. There are reports of successful collision attacks but these are far less computing intensive than preimage attacks and and of no use at all here. Even if SHA1 would indeed become useless for this use case some day it would be no big problem to switch to another hash function in relatively short time but you can of course use already one of these from the beginning. The only disadvantage of longer hashes is that they also take longer to compute which can be a factor here since the hashing runs in javascript and you may want to use it also on less powerful devices like phones.
  • The salt is a string of random data. I use 20 characters from a alphabet of 62 symbols [0-9a-zA-Z] which is 119 bits of random data that gets generated with a secure random generator. The salt protects the hash values against attacks with rainbow tables and all other forms of precomputed values which could be used to grab at least the weaker passwords from the network traffic with easily available computing power. Weak passwords are still vulnerable since they can be deduced from the hash and salt with dictionary attacks and brute force for relatively short passwords. But due the salt these attacks require considerable computing power for every attempt to find a single password.

Why is it not widely used?

  • I think it's mostly because the users at large are not really aware of the problem and thus don't request more protection. They also won't see any immediate benefit which means a website can hardly gain some accountable advantage form protecting their users passwords this way.
  • There is transport layer security which prevents against password sniffing and additionally allows to authenticate the server and protects the content against modification.
share|improve this answer
2  
I see a few problems with this. What if I'm using no script to start off with. Does that mean I can't login? Second, if someone is sniffing packets, it's still very easy to get the password info. As the salt is in plain text on the first hit, and your encryption is in javascript that is easily viable, it doesn't take much work for someone to figure out the password. –  Tyanna May 17 '11 at 17:45
2  
Yes, if you don't have javascript turned on you can't login. But this is no problem for sites that already depend heavily on javascript. Allowing plain text logins as well would of course be a option too. And you are wrong, you can't decode the password from the hash, even if you know the plain text salt. You would need to break the hash function, which is not yet possible. All you can do is running a dictionary attack against the hash which would be much more computing intensive than usualy, since you cant use rainbow tables to optimize breaking many passwords in a row because of the salt. –  x4u May 17 '11 at 19:51
2  
@Jarrod, what's your threat model, and what's the break? –  Peter Taylor May 17 '11 at 21:11
7  
if you're going to go through this much effort, you may as well just use SSL and get the additional benefits of that protocol that you don't get with this solution (such as the user being able to easily see that he is on a secure connection) –  Carson Myers May 18 '11 at 3:50
2  
So we're just throwing the old adage "Never Trust The Client" out the window with this one? –  Dalin Seivewright Mar 5 '12 at 17:11
show 9 more comments

In theory this doesn't give any extra security, but in practice this can be used to protect against "rogue sites" that don't hash your password in the server.

How exactly does this protect you? It sounds like all you want to do is hash the hashed password which is sort of pointless. Because the hashed password would then become the password.

There are many sites on the Internet that require login information, and the only way to protect against password reusing is the "promise" that the passwords are hashed on the server, which is not always true.

How about not using the same password for more then one site. The reason websites hash the password in theory is to prevent access to your account if THEY are compromised. Using the same password for multiple websites is just stupid.

If you did use javascript, all the "hacker" would have to do is, use the same method on the hashed-hashed-passwords. Once you have the hashed information its just time it takes to compute the password->same hash in the database that is a factor preventing access to an account.

share|improve this answer
1  
If your browser always hashes it the same way, then yes your hash can be used as a password everywhere else. But what if browsers assigned a salt based on the site (maybe the domain?) before hashing and sending that to the site? I think it's an interesting idea. –  Tesserex May 17 '11 at 14:43
1  
if it is on the client it is compromised, any salt on the client is in plain view, this is an illogical question. if you don't understand @Ramhound's answer you should not be writing code that needs to be secure, and start reading up on security and cryptography from the beginning. –  Jarrod Roberson May 17 '11 at 16:52
2  
When you are quoting the original poster, please format the text as such (select the text and use the quote icon just above the editor) –  Marjan Venema May 17 '11 at 18:19
3  
If the salt is known by the client and it is sent in the clear from a server, anything in the middle knows it as well. Never said, I needed to undo the hash, if you know the salt on the client, then isn't secure. –  Jarrod Roberson May 18 '11 at 1:11
1  
@Ramhound: I am not your personal editor, mate. And I did not complain, I gave you a suggestion. –  Marjan Venema Mar 5 '12 at 20:22
show 6 more comments

Why isn't it used? Because it's a lot of extra work for zero gain. Such a system would not be more secure. It might even be less secure because it gives the false impression of being more secure, leading users to adopt less secure practices (like password reuse, dictionary passwords, etc).

share|improve this answer
    
This is the best answer so far. –  Jarrod Roberson May 18 '11 at 1:17
1  
It's like Blu-Ray and DVD encryption. It doesn't even require a Key to unlock. The only "protection" it provided was that when DVDs first came out it cost more to buy a disc to copy it to than to buy a full copy of the movie. Of course now you can buy a dvd for a dollar and even more is the fact that the keys are public knowledge now. Same is happening with Blu-Ray –  Mike Brown May 18 '11 at 4:07
    
I think hashing a password client-side does add security. If I'm listening in, I can only see your hash, not your password. If the server sends a challenge (as it should) the hash is not even reusable. –  Andomar Jun 14 '12 at 9:13
    
I think x4u's approach may very well be appropriate for some applications where security requirements are somewhere between transmitting passwords on the wire and using certificates. I think some of the nay sayers are overlooking that the hashing of the password before it goes on the wire is done in addition to the standard server side credential handling. So the question is this: Does x4u's proposal improve security in the transmission-of-password-on-the-wire-scenario or not. I say it does. The key to realizing this lies in the usage of per-password salts. –  LOAS Jul 23 '13 at 9:19
    
The correct way to prevent MITM attacks is end-to-end encryption. TLS (https) exists: use it. Don't invent your own crypto schemes. –  Rein Henrichs Jul 24 '13 at 17:48
add comment

The solution is simpler than that. Client certificates. I create a client certificate on my machine. When I register with a website, we do a handshake using my client certificate and the server's certificate.

No passwords are exchanged and even if someone hacks the database all they'll have is the public key of my client certificate (which should be salted and encrypted by the server for an added level of security).

The client certificate can be stored on a smart card (and uploaded to a secure online vault using a master password).

The beauty of it all is it removes the concept of phishing away...you're never entering a password into a website, you're just handshaking with that website. All they get is your public key which is useless without a private key. The only susceptibility is finding a collision during a handshake and that would only work one time on a single website.

Microsoft tried to provide something like this in Windows with Cardspace and later submitted it as an open standard. OAuth is somewhat similar but it relies on an intermediated "issuing party". InfoCards on the other hand could be self issued. That's the real solution to the password problem...removing passwords altogether.

OAuth is a step in the right direction though.

share|improve this answer
3  
While client certificates are a reasonable approach for some use cases, they are not something that can be added easily to a website login. They require a great deal of cooperation from the users and depend on how secure the users private key is. The usage of a private key can be either secure or convenient but not both at the same time. –  x4u May 17 '11 at 20:13
add comment

Because it would add little to no value. The reason hashing is that if your database gets hacked, the hacker would not have a list of valid password, just hashes. Therefore they could not impersonate any user. Your system has no knowledge of the password.

Secure comes from SSL certificates plus some form of authentication. I want my users to supply a password so I can calculate the hash from it.

Also, the hashing algorithum would be on the server in a more secure area. Putting it on the client, it's pretty easy to get the source code for Javascript, even if its hidden referenced scripts files.

share|improve this answer
1  
This is the best answer. You should encrypt at the transport layer. Without doing that, the rest is not secure. Yes, you could write an encryption function... but that function would be visible to the (malicious) end users. Use SSL. –  pc1oad1etter Mar 9 '12 at 16:14
add comment

It is definitely possible, and actually you do not need to wait for a website.

Have a look at SuperGenPass. It is a bookmarklet.

It simply recognizes passwords fields, concatenates what you type with the website domain, hash it, mangles it somewhat so as to get only "admitted" characters in the password, and only then is your hashed-password sent on the wire.

By using the site domain in the process, you thus get a unique password per site, even if you always reuse the same password.

It is not extremely secure (base64-MD5), but you perfectly distribute a sha-2 based implementation if you wished.

The only downside is if the domain change, in which case you'll need to ask the website to reset your password because you'll be unable to recover it by yourself... it does not happen often though, so I consider it an acceptable trade-off.

share|improve this answer
    
This is what I was thinking when I read the question; it's practically useless for sites to do their own client-side hashing, but a browser extension that does it (using some salt based on the domain) would effectively nullify the risks associated with password reuse. Of course, the fun part comes when you try to log in from another machine... –  Aaronaught May 17 '11 at 23:32
2  
this isn't anymore secure than any other scheme that passs the password in the clear. It makes the password unique but it still isn't encrypted, but if I have a server in the middle, I can just grab the complicated but still clear password and use it as much as I want, it isn't changing. A hash isn't some magic bullet, it isn't even encryption, they are called cryptographic hashes, but that doesn't mean they are encryption. Doesn't matter if my password is password and or an SHA-256 of password with some salt that is know to the client, a man in the middle attach can capture it. –  Jarrod Roberson May 18 '11 at 1:17
    
@Jarrod Roberson: you can use the password of course, but you cannot reuse it for another of my accounts, which is the point. Therefore, if one of the website I connect on got his password base stolen, and they stored them in the clear, then my other accounts are safe. –  Matthieu M. May 18 '11 at 7:00
    
@Aaronaught: that is where it shines actually. Since the password sent is derived purely from the website domain you log on and a master password of your choice, you can login from any computer (and browser) as long as you have the bookmarklet. This is why it's somewhat more comfortable than a certificate. –  Matthieu M. May 18 '11 at 7:02
2  
@Jarrod: This isn't a security measure for the site, it's a security measure for the user. If everybody used a scheme like this, password reuse would be a non-issue. A MITM scheme could use the client-hashed password to gain access to that site, but only that site. That's where the improvement lies. Ordinarily you'd expect to be able to gain access to a lot of accounts by simply cracking one password, because that password is likely to be reused; in this case, the cracked password is practically guaranteed to only be valid for the site or database it was found in. –  Aaronaught May 18 '11 at 22:29
show 3 more comments

I like X4u's answer, but in my opinion something like it should be integrated into the browser/the html specification - as at the moment it's only half the answer.

Here's a problem I have as a user - I have no idea whether my password is going to be hashed at the other end when stored in the database. The lines between me and the server may well be encrypted but I have no idea what happens to my password once it reaches the destination - it maybe stored as plain text. The database admin guy may end up selling the database and before you know it the whole world knows your password.

Most users reuse passwords. Non technical people because they don't know any better. Technical people because once you get to the 15th password or so most people don't stand a chance of remembering them unless they write them down (Which we all know is also a bad idea).

If Chrome or IE or what ever it was I am using could tell me that a password box is instantly going to be client side hashed using a server generated salt and effectively sandbox the password itself - then I would know that a user could reuse a password with less risk. I'd still want the encrypted channels as well as I don't want any eaves dropping going on during transmission.

The user needs to know that their password is not even available to be sent to the server - only the hash. At present even using X4U's solution they have no way of knowing this is the case because you don't know if that technology is in use.

share|improve this answer
add comment

I think it's a good method to use when building something like a framework, CMS, forum software, etc., where you don't control the servers that it might be installed on. That is, YES, you should always recommend use of SSL for logins and logged-in activity, but some sites using your framework/cms won't have it, so they could still benefit from this.

As others have pointed out, the benefit here is NOT that a MITM attack couldn't allow someone else to log into this particular site as you, but rather that that attacker wouldn't then be able to use the same username/password combo to log into possibly dozens of other sites you might have accounts on.

Such a scheme should salt with either a random salt, or some combo of site-specific and username-specific salts, so that someone who gains the password can neither use it for the same username on other sites (even sites using the identical hashing scheme), nor against other users of the site site who might have the same password.

Others have suggested that users should create unique passwords for every single site they use, or use password managers. While this is sound advice in theory, we all know this is folly to rely on in the real world. The percentage of users who do either of these things is small and I doubt that will change any time soon.

So a javascript password hasher is kind of the least that a framework/cms developer can do to limit the damage of someone intercepting passwords in transit (which is easy over wifi networks these days) if both the site owner and the end users are being negligent about security (which they likely are).

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.