One of the sessions at SxSW talked about the importance of salting passwords in the database in case an attacker gains database access. The assertion is that hashing in the database is not enough, that the hash needs to be combined with salt. This got folks (including me) thinking and talking about this again, which is a Good Thing.
I completely understand and agree with this logic, and did a little poking around in my code to see if I could implement this before ran into a logical roadblock and remembered why I hadn’t in the first place. The approach I’m currently taking is to guard for security across the wire instead of security in the database.
Here is the approach I take:
- Hash the unsalted password in the database (not secure).
- When displaying the login form, set a single-use token that is also included in the form.
- On the server pull the unsalted, hashed password from the database and hash it with the single-use token, then compare that to the hashed value received from the login form.
By using this approach the hashed password being submitted over the wire from the login form is never the same (even though the password is the same each time). This means that a man-in-the-middle attack (think public WiFi) is defeated as the login credentials that are passed are valid only for that session.
What it doesn’t solve is having unsalted hashed passwords in the database that are vulnerable to lookup via rainbow tables if an attacker gained database access. Of course, if one were to salt the hash in the database and pass the salt down to the login form so that it could be included in the browser-side hash generation, it would defeat the purpose of the (secret) salt in the first place.
The question I asked is: which is more likely, an attacker gaining access to the database or someone sniffing traffic on the wire.
I believe the wire attack is a more likely vulnerability. People will generally connect to any available WiFi network (especially with mobile devices), with little regard to security.
However, though the wire attack might be the more likely you could make the case that a compromised database is the more dangerous of the two situations, especially in the case that you have a large amount of user data stored in a single database. In that situation, it might be wise to prefer to guard against a wide user data compromise instead of the wire attack that would only compromise access for a single user.
I guess it comes down to each application’s specific use case.
Another solution to this might be a public/private key encryption solution, but admittedly I don’t know enough about this (yet) to know how feasible it would be to implement with a simple user password input model.
Have another method of handling this? Think I’m wrong about wire vs. database being a more likely attack scenario? Think there is an absolute here that I’m missing? State your case in the comments…
This post is part of the thread: Passwords – an ongoing story on this site. View the thread timeline for more context on this post.
I agree that its more likely that attacker with hit over the wire versus the DB. But, If an attacker gets access to a DB they in theory probably have access to your salt formula and as a result could reverse engineer an attack with rainbow tables.
True, I should have clarified this as a “database only” vulnerability. If an attacker gains access to both code and database, then salted passwords are subject to the same rainbow table lookups (albeit with an additional step in the process).
That’s another good reason to optimize against a wire attack vs. a database only attack.
IMHO wire attacks are much more worthwhile to protect against.
The problem with database only, is that it seems rare only the DB is compromised. Normally it’s the last to be attacked, the web app being in front of the DB. The DB should be the most restricted (only the webapp needs to even communicate with it).
That said, you can pretty much solve wire attacks by using SSL which also verifies identity and helps against MITM attacks. IMHO more worthwhile than a JS solution. Overhead is reduced if you have SSL hardware on your server.
Agreed. SSL is a great tool in this mix, however my experience has been that few of my customers actually install and configure SSL when they install a web app. I want to do what I can to help in those cases as well.
I think I’m missing something here. I thought salt was public information designed to increase the size of the required rainbow tables. The salting function is just the hashing function and it is designed to be one-way. So a) it doesn’t matter if the salt is exposed publicly, and b) if you have a good hashing function, it’s hard to reverse engineer the salting even if you know
Am I misinformed?
That’s interesting, I hadn’t heard it looked at that way. Wikipedia says:
I think that a hash of a hashed string plus salt can make it harder to reverse, but once the algorithm is figured out it’s just layers.
Perhaps the best approach then is to check the protocol and require SSL for the app to run, unless the installer explicitly disables that check in the config file, in which case they assume the risk.
Setting up a self-signed SSL cert, or buying and installing one (basic validation is only a few dollars now) isn’t a huge deal. Most just skip the step to speed and because it just works.
Put a barrier there and people will second guess disabling a security feature.
IMHO all apps should require SSL for login. I have an SSL cert for my blog for the purpose of securing the contact form, and for login (most important).
I think that would result in a lot of requests for refunds from my customers… 😉
I doubt it. If they are running it without https right now anyway, they obviously don’t care. Changing a config is hardly a barrier to adoption (is it really zero config right now?)
It looks like you’re trying to build DIGEST-MD5:
however, that’s being replace with SCRAM:
using one of these schemes that have been fully-vetted by the security community is a much better approach, even if you have to pull it up into your application rather doing inside the protocol like SASL imagines.
I’m not sure what you’re wanting is possible. There needs to be a shared secret of some kind in order for authentication to work at all.
Basically, the client must send something that is what you store in the database, or which can be transformed into same through an algorithm.
Now, since the function of that algorithm depends solely on inputs from the client and stored values already on the server, there’s no way to secure it if they know the values on the server or what the expected response is. All you can do is to make it difficult (take longer to brute force). You can’t actually make it impossible.
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.
Sorry for the late reply, I just found this while stumbling upon the same problem. Here’s an idea: Until SCRAM authentication gets a wide implementation, why not use AES to encrypt the passwords based on a per-user salt and a separately-stored server key? (i.e. encrypted_pw = aes_encrypt(password,sha1(salt + serverkey)). This way you can still obtain the unencrypted password for use with challenge authentication. While not perfect (the security is still compromised if the server key is leaked, and the passwords are rendered useless if it’s lost), it adds a small layer of security to your database passwords.