Many applications require customers (don’t call them users!) to sign up with a username or email address to use the service.
If a user mistypes their credentials, security best practices dictate that an error message be displayed which informs the customer that there was a problem WITHOUT revealing whether or not the username was found.
The big guys got it right:
- Amazon: “There was an error with your E-Mail/Password combination. Please try again.”
- Google: “The username or password you entered is incorrect.”
- Facebook: “Incorrect Email/Password Combination.”
- Twitter: “Wrong Username/Email and password combination.”
This is really important for a few reasons, like…
- Protecting your customer’s privacy
- Preventing someone from downloading your entire customer list
- Making it (slightly) tougher to brute force a login
- Making it more difficult to socially engineer an account
Unfortunately, the login page isn’t the only place we have to worry about.
I happened to run into this problem again recently and did a bit of
research googling and I found some really nice answers on the Security StackExchange.
The answers list a few common areas where this can arise:
- Account Signup
- Forgot Password
- Modifying Account Details
Great. So, what can we do?
So, how can you tell the customer that they can’t update their email address to the one they just entered, without revealing that the username/account is already in use?
Well, like a lot of the other answers on StackOverflow and StackExchange…we’re asking the wrong question.
What we really need is a verification process, not a text change.
Here are a couple of the solutions inspired by the Security StackExchange:
1. Rate Limiting / Velocity Checking
Forcing a timeout between requests per session could help prevent someone from downloading your entire list, but it doesn’t do anything to protect an individual customer.
I could try to register firstname.lastname@example.org on OKCupid.com to see if he’s a patron of the dating site.
We already know that you should use a different password for every site/application, do we also need to use a different username/email?
2. Verification Emails
Another solution for this particular problem is to structure your application around verification emails. This not only protects your customer list, but you never have to reveal whether or not an address is taken…you just send (or not) a verification email with a link to complete the transaction.
Same goes for password reset and registration.
If the target’s email has been compromised, then they’re already in big, big, trouble. For many applications, email is your only way of verifying your customer’s identity.
The problem with verification emails is that they’re annoying to the customer and you can potentially send a lot of emails so you will still need the rate limiting.
There is also additional complexity to iron out but at least you can feel better about communicating the real problem to the customer once you’ve “verified” their identity.
It’s extra work, and it’s not convenient, but at least your customer is safe.
IANAE but the combination of rate limiting and verification emails do a pretty good job of mitigating the attack. There’s no information disclosure but the customer experience is diminished and there are a few usability decisions you need to make.
Please leave a comment if you’ve got any other ideas or suggestion.