I'm not a security expect, so be wary of my views.

Any site that has a "I forgot my password" button that emails you your password is horrible. If they don't have this feature, they might be horrible, its harder to tell. "Reset Password" is a way more sane feature to have (its possible to implement while still having some security).

Users are less than ideal: they reuse passwords, and use common passwords. Despite this, we can still have decent password based security.

Compromising your email

If you have an account, and anyone can make the password for it sent to your email, they can get your password if they compromise your email.

There are also similar issues with non-email cases. If someone stole my phone, they could login to my account with my provider since they have an option to text me my password.

This is very bad if you reuse passwords for your email login. Any account that you make and give your email address, and create a password that matches your email password can access all accounts you have that have an "I forgot my password" thing to email it. This is the worse case situation, don't do that!

The section on reuse below (especially the user side solution, since this attack involves a hostile, or flawed provider), provides a way to make this less of an issue. Overall though having "I forgot my password" buttons are a pretty bad idea, and having a place to recover control/access of accounts not be more secure than the individual accounts it backs is silly: be very careful with your email login credentials!


Users reuse passwords for different services. They also might accidentally type in a password for a different service instead (this happens a lot if you actually try and have many different passwords). This is very bad: you are telling random services your login info for other services.

Provider solution: Derive a service specific password from the user's password. Hash it with some service specific salt (ideally client side), and use that as the password.
User solution: Save as above, but before you hand over the password. A password manager of some sort ought to be able to generate such salts (it could just use the domain or something), let the user name them, and auto suggest the correct one based on the SSL certificate or URL.

These salts don't need top be secret. They simply cause the same password to appear different to different services, so if their data gets used (either by them, or someone who stole or bought their data), it won't let them know your password which you likely share between services, and accidentally entering another services password does no harm.

Of course, this still does not help if the user reuses passwords, and and someone manages to determine the actual passwords, not the derived ones: its simply a way to reduce the places the real password could be discovered to trusted areas. In the user solution, the real password never leaves the user's trusted software. If you can't trust the software (or people watching) you type it in, its impossible to be secure in this case, but it solves all other cases: thus it does as well as possible in this respect.

If this system is used, they don't know your "real" password you type in, so "I forgot my password" can't send you it!

Also, you want to include salt specific to the username, to prevent the same issue between multiple accounts on one service: its easy, so you might as well add the extra protection. More on additional benefits of this below when addressing some types of dictionary attacks.

Compromised Databases: How to minimize the harm from losing your password database.

My first principal of security is to make a total loss not very harmful if practical to do so.

There is no reason that someone stealing your password database should let them login to user accounts. Even if you encrypt it, lets assume they can also steal your decryption keys. Its still possible (and not even hard) to make this complete loss not very harmful, so everyone should do it.

Once again the standard tool of choice is a cryptographic hash. All you need to be able to do is check if a password is correct, so hash the password before you store it. Just use the same hash on the incoming passwords, and see if the hashes match. This makes it impractical to derive the passwords from the database.

But this is NOT enough. Cryptographic hashes are designed to be very fast to compute, and users tend to use passwords that are easy to guess if you make a million or so guesses. Thus the classic dictionary attack against a stolen password database still works. Assuming all data (encryption keys and such) were stolen, it is impossible to prevent this: if someone has all the data the server had, they can do what the server did, and verify if a password is correct. This means dictionary attacks can not be prevented in this case, but they can't be prevented in general either: no matter what you do, an attacker can try and login to the real server like a normal user.

How to make dictionary attacks, even when the attacker has every bit of data from your server, impractical, or at least very slow:

  1. Make sure that a successful attack on one account does not reveal the passwords of any other users (salt with username when hashing)
  2. Make it slow/expensive to try each password from the dictionary (use something like bcrypt or scrypt)
  3. Make sure successful attack on other databases don't reveal users with the same password in yours (salt hashes with something service specific)

Combine these, and you can make the attacker have to run their attack separately on every user in your database, and make each try of a password from the dictionary take some real computation time and power. This means you make dictionary attacks expensive (in time, and cost), which with both make less people bother, and gain your users time to change their passwords if you lose all your data to an attacker.

It's also a good idea to encrypt your database to increase the number of things which must be compromised (all keys, and the database itself) before such an attack can be started. Also, be sure to prevent online dictionary attacks agains the regular server. There are lots of approaches to this (making users wait between multiple login attempts on the same user account, IP blocking, proof of work to make a request, etc).

Once again, if you do this, you are storing a hash of the password, so if a site has "I forgot my password" to send it to you, you know they aren't doing all of these.

Fake server

Phishing schemes usually put up a server thats suppose to look like the real one, so a user will login there, and thus provide the login info to the attacker.

This is no more that a special case of password reuse. Its just like reusing a password from one side on another (the fake site). If you employ service specific salt user side, the problem is fixed (assuming "user side" is in user software, not just the client side on the site, since the phishing side would just leave it out). The challenge is differentiating between the two sites. Assuming we had a secure DNS system (we don't), you could just use the domain. Basically, the login will fail unless the salt is right, and if the account was created on a different domain, they would have to manually select the original (to get the correct salt) to be able to login, which they generally wouldn't do.

That scheme is pretty good, but it still has some flaws in the face if compromised DNS, and foolish users. A challenge response system is a good solution, especially url of origin is involved (and perhaps its SSL certificate if present). Perhaps the server issues a random string (with maybe a time stamp included), and the client hashes it with the password, url, and account name, and sends it back.

There is a bit of a trick to this, since what the server has is not the password, its something derived from it. So before hashing in the password, the client must derive this same thing, and use that, so the server can actually verify the response.

Man in the Middle

The above "Fake server" is not completely resistant to Man-in-the-middle (MITM). It prevents stealing the actual reusable login credentials, but it does not prevent hijacking a session, or spying on it. Use some actual encryption to deal with that part. There are all kinds of other scheme that could be employed, but why resolve a solved problem.

Copyright © 2011-2013 Craig Macomber