views:

694

answers:

7

I often make small websites and use the built in ASP.NET membership functionality in a SQL Server database, using the default "hashing" password storage method.

I'm wondering if there's a way to authenticate a user by hashing his password on the client and not sending it in clear text over the wire without using SSL.

I realize that this would only be applicable for users with Javascript enabled.

Or... possibly, this would be a great built-in capability for Silverlight (is this in the Silverlight roadmap?)


EDIT: I'm also looking for "degrees of security." Meaning, if there is a method that has some advantages over simply sending plaintext password, I'd like to know what they are and why.

I know there are lots of people who do small sites with logins (such as a family website or volunteering to make a site for a local cooking club) and don't see the need for purchasing SSL certificates.

+1  A: 

At least you have to use a salt for generating the hash. Otherwise the hash value is as "valuable" as the plain password when intercepted - at least on your site.

VolkerK
+5  A: 

This is a bad idea, security wise. If you send a non-ssl form that contains the hashed password, then anyone capturing traffic has all they need to login. Your javascript has to result in something that indicates success (a redirect, token passed to the server, etc). Whatever it is, the listener now can recreate that without proper authentication.

SSL was built for a reason, by people who tried a lot of other web authentication schemes. It is far safer and cheaper to get a cert than to try write your own safe authentication scheme that works without encryption.

Added for clarity:

Client side hashing alone is not safe. Say I have a form with the following inputs

<form action="signin.whatever" method="post">
<input type="text" id="txtUser">
<input type="text" id="txtPass">
<input type="hidden" id="hiddenHash">
<input type="submit" onclick="hashAndSubmit()">
</form>

where hashAndSubmit() hashes the password and puts it in hiddenHash, and blanks out the password field. If I sniff your submission and see the following fields:

txtUser:joeuser
txtPass:
hiddenHash:xxx345yz   // hash result

that's all I need as an attacker. I build a form with your user and hash value and I'm all set. The password is not necessary for a replay attack.

To get around this, you have to look at one-time salt values, or other schemes. All of which introduce more cost(don't forget developer time) and risk than SSL. Before you do something like this, ask one question...

Do I trust myself more than years and years of public testing of the SSL encryption?

Tim Hoolihan
Why does the Javascript (or other client side script) have to indicate success? Why can't it just send the hashed password to the server for comparison against the stored hashed password instead of sending the plain text password to be hashed server-side, then compared?
Traples
it's either or. if you hash on the client, then the password doesn't matter anymore, because an attacker can sniff the hashed password and do a replay attack. if you authenticate on the client, then you need only reply the success token. Either way, you have a problem.
Tim Hoolihan
This isn't just "do I trust myself," it's more about me possibly being genuinely ignorant of solution I've not heard of... so I'm asking. And, I'm curious about "degrees of security" not just what is the ultimate security only (as I just noted in my update).
Traples
To clear a little more of my abundant ignorance, can a replay attack that you mention, be alleviated by tracking host name or other identifying session data? Or, is this to subject to insecurity?
Traples
Anything like that would be helpful, particularly if you get it out of the IIS pipeline instead of form variables. However, there are man in the middle attacks and spoofing could come into play. I didn't mean to imply ignorance or sound harsh, sorry if I did, just relaying lessons learned.
Tim Hoolihan
No, you're not implying ignorance, I just like to over-estimate my ignorance... if that's even possible. While I agree with your answer, I'm choosing @jrista's for posterity because I believe it most directly answers the question and then points out the drawbacks.
Traples
+1  A: 

You could do this, but it would be just as insecure. The problem is that someone could capture the hash and replay it (just as they could the original password). I suppose you're providing some protection against the exposure of the actual password (in case they use it on other systems), but your system will be no more secure.

Draemon
+4  A: 

This is possible. This is actually what Kerberos authentication does, only with a little bit of added spice. To ensure that your authentication mechanism is secure, you need the following:

  1. A common hashing algorithm on both the client and server.
  2. A one-time salt value generated on the server and shared with the client.
  3. The original password stored in a database.

To securely authenticate a user via hash code, so you avoid sending the actual password across the wire, first generate a random, single-use salt value on the server. Send this salt value to the client, and generate a hash code from the salted version of the password the user has input. Send the resulting hash code to the server, and compare it with a hash code generated from the salted version of the stored password. If the comparison fails, discard the salt, regenerate a new salt value, and repeat the process.

The reason for the single-use salt is to prevent anyone listening to the conversation from capturing the hash code of the users password, which, when you use hash code comparison, is just as good as having the password itself.

Note that you need to keep the original password around, you can't hash it once on the server and save the hash in the database. If you need to ensure that the passwords stored in your database are also secure, then you will need to encrypt them before storing them. I believe that ASP.NET membership providers do allow you to store passwords encrypted, however, if you really wish to have a secure authentication mechanism that is difficult for a hacker to crack, then I would recommend handling password storage and retrieval entirely on your own.

Finally, I should note, that such a complex password transfer mechanism should be largely unnecessary if you use SSL to encrypt your connection during authentication.

References (for those who have never heard of Kerberos or SRP):

http://en.wikipedia.org/wiki/Kerberos_(protocol) http://en.wikipedia.org/wiki/Secure_remote_password_protocol

jrista
don't reinvent authentication protocols, reuse well established ones
Remus Rusanu
Could someone please explain why this was voted down? This is an entirely valid authentication practice that has been in use on many systems for decades.
jrista
@Remus: This isn't a new protocol, it is a well established one. Its part of Kerberos, which allows secure authentication across an unsecured network. http://en.wikipedia.org/wiki/Kerberos_(protocol) The password hashing mechanism is called SRP, Secure Remote Password protocol. http://en.wikipedia.org/wiki/Secure_remote_password_protocol
jrista
From your own links, look at the drawbacks. Does that look like a good list for internet clients? Clock requirements? http://en.wikipedia.org/wiki/Kerberos_(protocol)#Drawbacks
Tim Hoolihan
@Tim: Kerberos was just an example of a system that used SRP. The actual password-exchange mechanism described is not Kerberos, and as such doesn't intrinsically suffer from all of its failings. Kerberos is a higher level system that uses SRP, but SRP is just the very simple secure password-exchange system I described.
jrista
@jrista: Fair enough, there may be other authentication systems that can handle this scenario. I think the point stands, however, that this seems to be more risk, effort, and cost(accounting for developer time) than SSL.
Tim Hoolihan
@Tim: Agreed, as noted by the final comment in my original post about this being unnecessary and overly complex if you use SSL. I try to make it a point to answer peoples questions regardless of my personal opinions about the subject. While SSL is indeed the better option, I can't say what the question asker's requirements are or why those requirements exist. Better to offer up useful knowledge than hide it due to personal bias.
jrista
this one answer deserve an upvote
firefly
+1  A: 

You can send as post fields the username/realm/password hash following the HTTP Digest protocol. AFAIK there is no built-in client component nor server side component to generate/validate this so you have to do everything manually. It also requires your storage to store a specific hash format, see http://stackoverflow.com/questions/1000281/storing-password-in-tables-and-digest-authentication

The advantage is that you're following a well analyzed and understood authentication protocol. Don't roll your own.

Remus Rusanu
A: 

I found an md5 function written in javascript here

klez
Don't use md5 these days - it's pretty broken. Here's a link why http://en.wikipedia.org/wiki/MD5#Vulnerability
zebrabox
OK. You found an MD5 function. So what?
Rob Kennedy
@Rob: it's what he asked. he says "I'm wondering if there's a way to authenticate a user by hashing his password on the client and not sending it in clear text over the wire without using SSL." and that's a way to do it.@zebrabox: sorry, didn't know
klez
+1  A: 

You can implement your hashing algorithm client side (in javascript) and send only the user name and hash result over the wire. Note that in order for this to be secure the hash must be salted with a string provided by the server, and the string must be unique for every request. The sever still needs to check whether the hash is correct or not and authenticate the session.

landon9720