I think the real lesson here is that if emails should remain secret you should not indicate upon signup whether or not a user exists with that email.
Always send an email.
If that user already exists, make sure the email says "We noticed you're trying to sign up again. If you didn't do this, someone else is trying to sign up for you." If that user doesn't exist, send them the typical signup message.
The author has some great security tips in the "what should I do instead" but I don't think the instead portion is accurate. Keep private information private, and make access to public information as easy as it should be.
If emails are public, shoot, use a websocket connection to style the login field in real time and show the user whether or not the email they typed is valid.
Please don't always send an email. A malicious person can now start signing up every day with a bunch of emails resulting in users who do have an account receiving an email from your site daily/hourly saying "we noticed you're trying to sign up again". At which point they become annoyed with your service and either unsubscribe or delete their account.
Hotmail do this everytime someone tries to reset my password which happens almost daily as I have what turns out to be an account name that is in demand and it's really irritating. And there is nothing I can do to stop someone attempting to reset my password - I have 2 factor switched on so they won't be successful.
Of course you can add more logic in to try and be more intelligent about when the emails are sent, but most sites won't get this right when they can't even store passwords correctly.
An attacker could already do this via nearly every service's "forgot my password" functionality, as you noted yourself in the case of hotmail.
As the original author noted, rate limiting is also a fundamental requirement for security. Eventually no more emails are sent because the offending IP addresses are effectively blocked.
Make email notifications an option for users (enabled by default, with an easy link in the email to disable), and you ensure your users that your service is secure, while giving them the ability and easy path to ignore it.
Re your Hotmail problem, personally I would spend 30 seconds configuring sieve to filter those annoying emails into my Trash so I never have to see them again. Problem solved.
Forcing the user to interact with an email client during the signup process before they've confirmed the availability of a username might be good for security, but it's a horrible way to gain users. That's a very high friction process.
I generally agree with this comment, however.
Hmm, I do see your point, though I'd propose that usernames are more often than not public information. That's been my experience at least.
The difference for usernames is that they may or may not be shared across services. They're a bit more transient to the average user than an email is, though only a bit.
That said, it depends more on your use case than anything else. If any information is private information, it should remain private. Otherwise, I say make it easier to access that information, and be consistent.
To be fair to those implementing the example login systems as well, not all malicious attackers are hackers. It could be an angry ex who wouldn't necessarily think to try creating a new user before proceeding with their password-mashing attempts.
"Bad login combination" and variants do avoid information leakage. It's just not consistently enforced across all surface area. As another example, I believe Amazon public wishlists are searchable by email. That alone can net you an easy list of logins to brute force or check against existing email-password lists.
I think it's most likely that these services are avoiding the "that username exists but it's not actually yours" conundrum while keeping code (and UX) complexity to a minimum.
True, but many site use the email address as the username and require you to validate that email address before you can do anything anyway. Those sites, at least, have nothing to lose by adopting this approach.
Let them signup again. Then send them an email asking that they signed up for a second time and if they wish to update the existing information with the new information provided in the "fake" signup process.
This is why I like federated login with the options of Google and Facebook. Why go through the hassle of creating a new password and sending a verification email, when the user can just click a couple buttons to sign in with a service indefinitely? The username can be chosen afterwards and never has to be re-typed.
I know, but it's so much easier. It's not like I can't look up someones email account manually without federated login, plus then I no longer have to store passwords.
Of course, aside from my own projects, the only service I've seen that exclusively does this is Fancy Hands.
I agree that it's easier, and if you're only getting a unique identifier from that service (as well as a token), then it's really not unsafe. For the purposes of login, data sharing is unidirectional.
The problem is that Facebook totally mismanaged their apps when they first launched, and a lot of people were permanently turned off to "Connect to Facebook" functionality by random apps posting under the user's name.
My account was recently abused by Glassdoor, which fervently promised not to post anything to my friends, and then immediately did so.
My trouble with these things is that they invariably support multiple services, all of which I have accounts with, and I can never remember which one I'm using for any particular service.
This doesn't really work that well, I realize - when users mistype their e-mail, they get their registration sent to some random address, and they get zero feedback on what went wrong. From their perspective, the registration worked and they just got no e-mail. Bad experience.
Security is all about trade-offs. Sending emails puts a bigger barrier between signup and first sign in. It is probably a better business move to slightly inconvenience some existing customers rather than slightly inconvenience all potential new customers.
What I'm saying is that every "signup" event should appear as if it was a valid, brand-new signup as far as the web user is concerned.
The email will be sent regardless. If it's a valid new signup, then the user gets a transparent experience. If the user has already signed up, send them a helpful "hey, you've already signed up" message in their inbox.
In case it was an attacker, maybe check the IP against known IPs that have had valid logins. If it's a new IP, add a section to the email message that a potential attacker may be trying to login and that no action is required, etc. Whatever fits your business case.
You're ignoring that most modern apps will give you rudimentary account access even before you confirm your email address. Which would be difficult to do if that account already exists.
My answer to this problem would be to let them in anyway. Store all session data with a cookie or (brand new) UUID, perhaps persisted via localstorage for the long-term users.
The email should still indicate new or existing user, and provide them a link that they can use to associate said UUID with their login and pull all the data onto their account as if they'd been logged in the whole time.
They'd need to be informed that all account data is accessible only on that computer, at least until they've confirmed their email address. I kind of imagine this is the existing behavior for many applications, though.
Additionally, if the service doesn't require emails to be authenticated, then they shouldn't be using them for much more than account recovery or notifications (once authenticated). Otherwise, I can sign up for that service with somebody else's email as long as they haven't signed up before, and then if that person ever wants to sign up for this service, either they're out of luck or the original (perhaps misguided) customer is out of luck.
That was the inconvenience I was referring to in my post. Either a new user needs to verify their email before using the site or you need someway to immediately tell the user that an account with that address exists.
This process also won't work for the small minority of sites that don't require email adresses. HN is one example.
And the entire point is moot for most social sites as it is trivially easy to check for the existence of a user by going to their profile page. Why bother going through all this email trouble when I can just go to twitter.com/TheUsernameIWantToCheck to see if that user account exists?
> Either a new user needs to verify their email before using the site or you need someway to immediately tell the user that an account with that address exists.
> Why bother going through all this email trouble when I can just go to twitter.com/TheUsernameIWantToCheck to see if that user account exists?
I totally agree. Twitter usernames are hardly private information, though. As I said, make sure truly private information is kept private.
Keeping in mind the UX, though, most users may not realize how easily their user id ( email/username, etc.) can be discovered. Seeing the login screen confirm that their username exists but their password is incorrect may in fact scare existing users away.
Determine what's best for your demographics, and ideally A/B test the heck out of it.
This is the actual concern. If you require an email check before someone messes around with the product, there's a potential dropoff that people can (rightly) be concerned about.
It's already pretty common to require clicking a verification link in an email to complete registration. If you're using someone else's email on the registration page, you're already doing something fishy, and this prevents you from discovering that the email is already in-use. To a legit user, everything looks normal (and to a legit user who forgot they had an account, they'll get a simple reminder in their inbox when they look for their validation link, possibly with forgot password instructions included).
Of course, this all goes out the window if you're not using emails as usernames.
I think it makes the signup process fairly simple and easy. At least, it doesn't complicate it. Email confirmations are almost standard anyway. The only difference is that by doing it this way, you don't reveal whether a user already exists with the email in question (the email is the username).
I have a hard time seeing what friction is added, though, with proper thought. If you don't require email validation but use it as a unique login identifier, then a malicious body could DOS all future users via bulk signups. DDOS required if you use rate limiting on signups. Slightly different application of the attack but still a denial of service.
Even a non-hacker could block another user from signing up by simply creating an account with someone else's email address.
If you don't use it as a unique login identifier, there's no problem at all. New users use their username to login.
This is important. It is not always necessary or appropriate to try to maintain the secrecy of otherwise public, directory information (like email addresses). Unless you are, say, FetLife, it doesn't actually make that much sense to hide the fact that joe@example.com has at one point signed up for your service.
On the other hand, associating joe@example.com with posts he thought were anonymous is an enormous violation.
Leaving security aside, "incorrect username/password" is still the more correct and useful statement.
Consider the case where you mistype your username (email). For sites like amazon, gmail, hotmail, yahoo, twitter, etc, it is entirely likely that the mistyped username is somebody else's valid username, you typed the password correctly, and "incorrect password" would hide the problem.
I've worked with a CRM product that allowed non-unique usernames. That's right the usernames could be duplicated, so we had like 10 jsmith's. It would parse the username/password combo, and if one matched, that's who you logged in as. I never got to test what happened when jsmith had the same password as another jsmith. I'm sure the results would have been terrifying and hilarious. Apparently, the history here is that it used to log people in using their email as their only username, but someone here didn't like that and the vendor tacked on this half-assed solution. So you email is your unique identifier but its not used during login.
I suspect there's a lot of poorly written software that still does stuff like this. The message is still valid in these cases as well.
I'm going to guess when a new jsmith comes along and tries to sign up with the same password as another jsmith, you get a helpful 'Sorry, that user name and password combination are already in use.'
Anything other than allowing the user to register with the same username and password as someone else will already give it away, so I don't see the harm in spelling it out.
"Password does not match our records for username/email XXX. Please check that both password and username are correct."
Responding to below This reads to me like a more verbose version of "Incorrect username or password."
Note this version is not wordsmithed and could probably be done better but the goal and inherent difference of this to the original is to let the user know that the username exists and that its the password which does not match.
Read the proposed message a few comments up. It actually says "username & password do not match the records we have for username XXX", thus implying that username XXX is a valid username. "Username or password is incorrect" does not indicate whether the username is valid or not.
This doesn't solve the problem for me. With some bank/credit card sites my username is "username". Others require a number and hence it's "username1" or "username!4". When I get rejected upon login it would be nice to know if I need to cycle through usernames or passwords.
That statement doesn't help the user fix a problem. Either you tell the user that one of the items is incorrect - "This password does not match our records" or "This user name does not match our records". Simply stating "Incorrect username/password" isn't sufficient enough information to prevent the user from making the same error (or even a different one) again.
Here's what I tell the developers I work with: Design for the users, not for development ease. This pattern has been successfully implemented by literally hundreds (thousands? hundreds of thousands?) of websites, so there's no excuse for trying to cut a corner and try to concatenate use cases. Either the user name is right and the password is wrong, or the user name is wrong and the password doesn't matter, or both are wrong and through some miracle of absolute unicorn user error they've managed to log in to someone else's account - at which point you have a different issue altogether.
You didn't really address the parent's point, which is that their misspelled username might match another real username. In this case, telling them that their password is incorrect is actively sending them down the wrong path, because they are likely to try fixing the password field rather than the username field.
Ignoring the fact that doing that would be retarded, if you're following modern practices and hashing passwords with KDFs that's not really possible without killing your server.
More likely, people won't forget how to spell their email address, or make a mistake in typing it that isn't immediately obvious; they might not remember which of their emails they used to sign up, though, even if they only have a couple. No one else can sign up with an email address that belongs to you.
I've seen mistype rates of close to 20% without the second field. Still, my boss won't allow me to put in the second field because he feels it would hurt the user experience.
You would still have the issues described in the OP. If it says "username incorrect" only when that user does not exist, you can still figure out a username by just trying them with a random password. If you get told "password incorrect" you know the username you just tried already exists.
I actually have two amazon accounts with the same email address (username), one has prime and the other one doesn't. Sometimes I type in the 'other' password and get the non-prime account and get confused.
If either the username does not exist, or the password does not match the existing username, then "incorrect username or password" is correct by logic. It might be incorrect if assuming xor meaning, because both could be wrong -- username and password.
The parent's point also was that the service can not identify which one is wrong. Was it the username if the password did not match but matches any other account?
> No, that's highly unlikely.
Why should it be unlikely to mistype the username? Misspellings happen. Some people check what they entered, some don't. People confuse their usernames when they have many. One username might be someone else's on another service. Etc.
> If the password doesn't match, just say so.
Which is wrong if the error lies with the username, not the password, and the mistyped username happens to exist.
>99.9% of websites on the Internet will only let you create one account for each email address. So if you want to see if an email address has an account, try signing up for a new account with the same email address.
While this is true, it's perfectly reasonable to require a captcha before allowing a new account to be created; greatly limiting the speed at which an attacker could enumerate emails. While it's not going to stop targeted attacks, it will mitigate mass brute forcing of weak passwords.
Regardless of the ease of username enumeration, all of the author's points about what to do are great for most sites. Rate limiting with exponential backoff and 2fa are some of the cheapest and most effective means of increasing the security of your app's authentication process.
But requiring a captcha before validating the uniqueness of each username would be pretty annoying for large websites where many of the usernames I would choose are already taken.
To be fair, parent was specifically referencing email address as the unique login credential, not a username. Presumably if your email is already taken you're not going to get frustrated at a CAPTCHA
Which doesn't matter, because there's no point in keeping usernames secret (and thus no point providing a captcha) unless those usernames are email addresses, in which case it's unlikely that the username you want will be taken.
Only if the returned error code timing for a bad username overalps bad password most of the time. Displaying an obscured error only serves to harm the real users and is of little benefit to the system.
Unless you delay all failed attempts to login by a random time of 500-2000 ms, it's unlikely you'll see much improvement in response rates... having such a random delay is probably helpful anyhow.
But there's no good reason to have a username at all unless users interact with each other or the web-going public, in which case the username is a public part of the URL. Services like twitter or github need @usernames. Other services should just use email addresses.
It's only useless if the website reveals the username elsewhere, but that doesn't have to be the case.
Consider the case when the primary usernames are always emails (many sites do this), and signing up for an account is simply done with entering an email and a password. Then, when someone submits a signup form, the website can:
- Check if an account with the email exists, and if it does, whether the given password matches the existing one.
- If both are valid, log the user in, optionally showing a message saying “there was already an account with these credentials so we logged you in”
- If an account with the email does not exist, or if it exists and the password doesn’t match, return a message to the user saying “please check your email and follow the validation link”. The user can’t tell if the email exists or not.
In the backend:
- If the account did exist, send an email to the user saying “someone tried to sign up for an account with your email, please let us know if it was you. and here’s a way to reset your password if you forgot it”.
- If the account did not exist, send an email verification link, which then redirects to a page to complete the user signup
Same with password resets, the success message can always say "check your email".
There are ways around revealing the username. But I agree, only doing this in the login page is useless.
If you have to validate email addresses, which I believe you do, what I suggested doesn't add any more steps so I doubt it would cost anything. To the contrary, given that the initial user signup is so simple (just an email and password), users will be much more likely to complete it compared to other signup forms that require more data. Once they are logged in and on your site, you can gamify whatever portions of the profile you need filled, that is, if you need any more data (most sites like hackernews don't).
Actually I'm wrong about hackernews, you'd need a username, but still, you can choose that after you sign up, and you shouldn't be able to log in with that username, that should only be a public handle for your account on forums, comments, etc.
> Consider throttling invalid login attempts by IP address or subnet.
Oh hell no.
First off that is completely ineffective. Botnets are common and inexpensive. But worse still a lot of users often share a single IP (e.g. university dorms, businesses, public wifi, etc).
I agree with the first part of this article (i.e. that it is trivial to "prove" a username is valid, and that worse error responses aren't accomplishing anything). But that advice is poor.
> Check submitted passwords against a dictionary of common passwords (123456, monkey, etc) and ban that traffic extra hard.
That seems like a lot of engineering work. Plus the workload of loading up a dictionary and doing a lookup upon each login is resources that frankly could be better used on a slower hashing algorithm (to slow logins and make stored hashes stronger).
> Exponential backoff (forcing attackers to try again after 1, 2, 4, 8, 16.. seconds) is useful as well.
Just open a spreadsheet and determine how long it would take to test 1500 passwords. 1500 is a "short" dictionary of common passwords. Even a 1 minute delay after each 2 attempts (or 2 minutes after 4, or 4 minutes after 8, etc) means 12.5 hours of attempts.
I like to set the attempts really high with an equally high lockout. So no normal user will see it. Most users do a password reset after the fourth or fifth attempt, so if you set it on 8 attempts with a 4-6 minute lockout then the majority of users will never run into it.
Instead of focusing on these kind of hacks why not just:
- Set no maximum password length (250+ characters)
- Set the minimum to at least 6 or 7
- Get a password score widget (e.g. "weak" "normal" "secure"), traffic light, to encourage better behaviour
- When a password is set check it isn't in a common password dictionary (a lot of score widgets integrate this!)
- You can use Javascript to check a password dictionary as it isn't a site-security feature, and anyone who goes out of their way to bypass it only has themselves to blame.
- Agreed on 2F, Google Authenticator is trivial to integrate. The only remotely "hard" bit is generating the QR code and a lot of libraries exist for that express purpose.
- No clue how you'd integrate LastPass...
- Account Alerts are extremely useful. As are admin alerts. Too many sites get no warning when a lockout occurs, it is pathetic.
* Concurrency -- I can check a lot of passwords at once. Are there race conditions in the backoff? Can I check 20 in one second? 200? What about all 1500? (yeah, that's not subtle and alarm bells should go off).
* Alternately, one can iterate usernames against common passwords, especially if usernames are known. (and as a subset of this, if accounts are locked after n tries and usernames are iterable, that's a DOS waiting to happen)
If someone can guess the first 72 characters of your password, they probably know the rest. e.g. They have access to your password manager or you are using a common phrase.
I still wouldn't limit a user from entering in a longer password. I'd display a warning if they attempt to enter in a 73+ character password to inform them that passwords longer than 72 characters offer no additional protection.
That's a bug. Bcrypt doesn't truncate, it simply doesn't handle longer passwords. And you can pretty safely use another hash before feeding it into bcrypt.
I have to agree with the parent here... There are other ways to add security, and having an obscure error message doesn't really improve things by as much as the error message can cause real users to go down the wrong path.
Who are you "agreeing" with? Neither me nor the article is arguing for inexact error messages. We both agree that registration pages leaking that information make hiding if a username is correct a pointless exercise.
On that point me and the article are in complete agreement.
Exponential backoffs also have the problem that it makes it far easier to lock someone out of their account. Or rather, it makes it possible to lock someone out of their account for an arbitrary amount of time.
> When a password is set check it isn't in a common password dictionary
I agree with this with short passwords. But for passphrases? No. I find it rather frustrating that (ex) diceware passwords are often rejected as too insecure or flagged with a nasty warning.
> I agree with this with short passwords. But for passphrases? No. I find it rather frustrating that (ex) diceware passwords are often rejected as too insecure or flagged with a nasty warning.
I too have ran into that issue. Instead sites doing:
password.Trim().Equals(<dictionaryItem>);
They do:
password.Trim().Contains(<dictionaryItem>);
So if you do a pass-phase or full sentence they'll call your password insecure for being a common dictionary word (even if it is 20+ characters long).
That's why score systems are better overall than any one single check. All parts of the password should be considered (e.g. length, complexity, commonality, etc).
> Exponential backoffs also have the problem that it makes it far easier to lock someone out of their account. Or rather, it makes it possible to lock someone out of their account for an arbitrary amount of time.
Why not allow the unlocking of an account through email and 2fa?
An email like, "Hey, we've locked your account because we've received a ton of incorrect login attempts. To unlock your account click the big button below OR visit www.example.com/longrandomhash"
And then have the user login again (and potentially use some sort of 2fa like facebook/github/google code generator).
> Just open a spreadsheet and determine how long it would take to test 1500 passwords.
After about 58 attempts the sun would have exploded. After 1023 attempts my spreadsheet application can't cope with numbers that big.
None of the author's recommendations conflict with the practice he is advocating against.
I think websites say "Bad combination" not because usernames are treated equally with passwords, but because you don't have a choice but say that.
If I tell you that your username is incorrect, am I telling you your password isn't? This would be silly, because if the website is new and I know a password is correct, then I can either find the username out there (if the website is social), or pretend I forgot my username and have them give it to me.
Assuming that's not what I am saying, then the user is surely to have a bad experience anyway, since they will need to figure out a wrong username, and then in the worst case, a wrong password. When you say a "bad combination" you at least eliminate a possibility to mislead them into thinking only one of their credentials is wrong.
> I think websites say "Bad combination" not because usernames are treated equally with passwords, but because you don't have a choice but say that.
Of course you do.
> If I tell you that your username is incorrect, am I telling you your password isn't? This would be silly
Of course it is, a password is checked against a username, not against the whole database. If the site is telling you the username is incorrect it's telling you just that: the username is incorrect. It wasn't able to go any further and check the password since it has no idea which password it should check for (or even, if you're correctly storing passwords, which salt it should use for the password check). Your criticism doesn't even make sense.
His point is that it's not uncommon to be unsure which piece of data the user got wrong.
Consider that on any decently sized website, you're going to have a lot of cases where someone's trying to log in and they typo their username into someone else's username (e.g. if you tried to log in as "masklin" and that was taken). This looks to your server exactly like a wrong-password, but it's not.
If there's genuinely no user by that name, sure, tell them.
If I tell you that your username is incorrect, am I telling you your password isn't? This would be silly, because if the website is new and I know a password is correct, then I can either find the username out there (if the website is social), or pretend I forgot my username and have them give it to me.
Not exactly. Multiple users could obviously have the same password but not the same username. Telling an attacker that the password is correct doesn't narrow down the possible user names it could have, <n, thus still meaning the attacker must theoratically try all valid username combinations with that password unless they have some way to narrow it down.
I mentioned exactly those what I think "some way to narrow it down" is, mainly new websites with significantly less users, websites where its common to have your username known in public, and even websites that allow you to query their APIs for username data.
I guess I don't see how that would matter if the website were new. You still would have to obtain a username list prior to new users signing up (assuming they use the same password as the one you're trying) and even then you're also assuming the website doesn't detect the intrusion and advise users to change their passwords.
"Sorry, we don't have a <name> in our database" isn't misleading. If the user enters an incorrect password too, the subsequent message "Invalid password for <name>" will let them correct it.
Perhaps misleading was the wrong word, but as you said it yourself, saying that would lead to a user experience that is much worse than a simple "Bad experience", which is exactly my point.
If the username is wrong, and you don't tell them, they will spend several tries on passwords that will never work.. because the user is invalid.
I have a number of sites I don't use often, that I wind up having to do a password reset on to then find out I'm not even using the right username... there was literally no gain from this... Any hacking attempt can do the same to determine if a username was valid or not.
It's making things easy for machines to do harder for people to do, which is the wrong approach to security.
Except that entering a registered email will likely result in the legitimate user receiving a password reset email that they did not request, thus immediately raising suspicions that someone may be attempting to access their account. Using the signup form is a much better approach.
Some sites don't. They instead say "if an account with that email address exists we've sent you an email with the reset link". That seems like a nice touch, but it's pointless if you can still find out that a given email address is a registered user in some other way (such as by trying to sign up with it). So it's just another variant of the "invalid username/password" message.
It is very annoying that visiting a site that you know you have an account on but cannot remember your username. The rate limiting feature seems to solve most of the issues with giving the user a chance at some feedback.
Thinking this is only about security is shortsighted, IMO. There are cases of typo-ing the email address, or entering a non-standard email address, which happens to match another.
ryan@gmail.com -> ryan@gmaail.com probably would have some benefit to UX in saying "email address does not exist", but ryan@gmail.com vs. ryanl@gmail.com both exist.
What I'd probably recommend instead, if you do decide confirming account creation status makes sense, is judging by cookie or IP. If 10.10.10.10 has previously logged in as ryanb@gmail.com, and I enter ryan@gmail.com instead, it might make sense to poke on the email; if I enter ryanb@gmail.com and have an incorrect password, maybe suggest bad password. (of course, if you have a cookie, you might as well pre-fill the login; if you have an IP match, probably not).
The security tradeoff here exists but isn't huge. There are definitely cases where the user benefit (and thus reduced bounce rate) of suggesting error in username or password would make sense. The biggest security issue is confirming "does this account exist at all?", because email addresses tend to uniquely identify users, and you need some other mechanism to prevent this -- either automated (captcha would work) or targeted (in which case it's quite hard).
I'm actually in favor of per-action security checking vs. "logged in or logged out, all or nothing".
This problem is often referred to as user enumeration, which seems like a misnomer to me.
Whatever you call it, it's good to keep in mind that Google, Apple, Facebook, and Twitter are vulnerable.
The most interesting facet to user enumeration is privacy. If Alice knows Bob's e-mail address, is it right that she can easily check with Carol's web system to see if Bob has an account with Carol? This is like calling a hotel and asking if a certain person is staying there. It leaks information confirming that two parties have a relationship.
What makes the privacy aspect especially interesting is that user enumeration is a bigger problem for small websites than for the Googles and Facebooks. This is because it's not much of a privacy breach to be able to test if a given e-mail address is on Facebook; big whoop, almost everyone is. But it's a much bigger breach to be able to test if a person is a customer of an illicit service. Most systems sit somewhere between those two extremes, and each needs to decide whether to prevent user enumeration.
The main point the author tries to make is quite matter-of-fact: If you are going to try to prevent user enumeration, then you have to do it for real, which usually results in less friendly account creation and password recovery systems.
The article does not point out, that not teling visitors which of password and username were wrong on login pages is a useless measure, it shows that there is a second way to find out correct registered email addresses on most platforms (by trying to register them).
This can be easily fixed by sending email conformation tokens prior to creating the user account and informing users in this email, in case they already have an account.
I don't agree with the author's premise wrt to usernames.
Often, you will login with a username, but the password recovery form will only accept an email. You might be able to correlate these two if you have a lot of data from other, external attacks, but unless if I noticed correlation between recovered passwords and account break-ins, I wouldn't worry about this.
There's a security tradeoff, but sometimes security must be risked in the name of functionality, or you'll have a lame product. Or, you can have both security and functionality, but to the detriment of UX.
Take leaderboards for example. If you have a leaderboard for your app/game, you'll expose user's username (and thus, sign-in name, as is often the case). You could mitigate this by: having a separate login name (ala steam), or using an email (which exposes people to the recovery exploit), but it doesn't make the UX any better.
In the end, I'd say trying to protect against username/email guessing attacks is probably unnecessary. There are better ways to approach security.
Alternate view, I hate sites which require login & password, especially to only view content. I try to ignore every such site, because those are designed really badly. As well as I don't get it what's the correllation between email and registration. I don't want to give my email, nor I want to register. If I need to give email, I can give any random temporary email. Signup procedures on many sites are horrible. Best sites do allow at least accessing content without these hindrances. Logging in, especially on mobile, is painful anyway. Using some kind of federated login is privacy issue (in most cases), so it doesn't solve anything either. For lulz, how about just PGP signing nonce? They can verify it against my public key. PGP also allows me to easily create as many parallel identifies with strong authentication as I want to.
The article misses the point that on many sites this is not a security feature, more a privacy one. I have used the 403 http status rather than 401 in the past for this exact reason.
RFC 7231[0] suggests something similar
"An origin server that wishes to "hide" the current existence of a forbidden target resource MAY instead respond with a status code of 404 (Not Found)."
with RFC 7235[1] suggesting the use of 403.
"A server that receives valid credentials that are not adequate to gain access ought to respond with the 403 (Forbidden) status code […]."
As the article notes, you can trivially get around that "privacy feature" by trying to sign up with the email. If it lets you sign up there was nobody there, if it does not the email is being used by somebody else. Most sites will reject you immediately if the email is already in the system.
> RFC 7231[0] suggests something similar
Well no, RFC 7231 suggests that rather than telling an authenticated user he does not have access to a resource you can tell him the resource does not exist at all. It has nothing to do with the authentication itself, and certainly isn't suggested (let alone recommended) as a response to an invalid authentication attempt.
> valid credentials that are not adequate to gain access
How does a clear statement that the user's credentials are valid but don't give access to a resource have any relation with the rest of your comment?
If it matters, you can make it non-trivial. As with most privacy attacks, you can target an individual pretty easily.
But, if you're trolling for lots of users, the "new account" feature will have a much lower operational tempo than the authentication workflow, and for a privacy conscious organization, you can do things to make it harder for attackers. Examples: Captcha, data input validation, risk scoring, don't provide immediate confirmation, etc.
Revealing that the email address is a valid system account isn't a particularly useful piece of information to a user who isn't remembering a password. john.smith100000@gmail.com is probably taken by another John Smith. It just isn't a useful piece of information.
Given that I have received downvotes I'll try more concrete example. Imagine that you start dating a someone and they discover your email, maybe you email them. Now they then take that information and try and log into a site that you do not wish that others know you use, this may be a porn site, it may be a group that you associate yourself with, say even a feminist forum. Now if you respond that it's the wrong password people are able to deduce (given that there is also a wrong username error) that you are a user of that service.
Imagine you put your email on your cv and this is done to see if you a member of a democrat or republican website, and you are not offered a job based on your political views.
Imagine that you use your email to sign up for a government service and they take that email, do as described above, and use the information in the future to discredit you in some way.
Maybe I have missed the point, but I personally think that this is a also privacy issue and only looking at it from the perspective of UX may have undesired consequences for people.
It is certainly the case that there is a privacy issue here. However, that doesn't substantially undermine the strongest point presented in the article - that the email is already exposed, usually by refusing to create a new account if one exists with that email and it's sometimes also reported when you ask for a password reset email.
I agree with you that the thing to do is fix those issues, though, rather than abandon it here as well.
I think that could also be solved relatively easily. Just flash that you are sending an account activation email to the person trying to create an account and email the already registered user with a notification that someone tried to sign up with their email address.
I would rather not work somewhere where they both care what my political views are and would go behind my back to find out instead of just asking me. Likewise, if someone I date starts spying on me this way that's a no either way and I would rather know about it when they try to throw something in my face than unknowingly date a creep.
I do think there is a privacy issue, but I think it is rather minimal and as the sibling poster states, the email address is already exposed.
As many have said if you simply rate-limit with captcha and block it complicates checking against all emails via bots etc.
This rule doesn't apply well to say the majority of b2b systems that don't have account creations public. Thus now I can phish for users and send them targeted oh reset your password here emails because I harvested them from some other hack. Remember it is not always the password that is the weak link it is the user as well.
So calling it useless is shortsighted, yeah for many basic sites it is simple to say yeah tell them what is wrong. That is why they created the picture login to go with the email to ensure you are logging in on the right site. If anything you aren't sure try forgot password with your email.
Source: Real experience building auth systems for large corps.
I'd be concerned that if hackers found out their login attempts were increasingly rate-limited (2 seconds, 4 seconds, 8 seconds, etc.) then they would just use that instead as a DoS attack and run that rate limit up to weeks or months if possible.
Send email to email address on file stating "someone has attempted to log in to your account multiple times..." only after multiple unsuccessful attempts.
What about a flat rate-limit of something like 30 seconds (or something similar) which is low enough that a user likely wouldn't be that irritated by it, won't be a severe DoS and is likely sufficient enough to hinder illegitimate login attempts?
Interesting premise. I think the original behavior is partly correct. The combination of user name and password doesn't match. Either one could be incorrect. Say my usual login is steven@example.com, and I do know my password. If I try to log in as stevon@example.com with my correct password, it is conceptually NOT the password that is incorrect. The user could legitimately make such typos, and should probably check both fields.
On the other hand, this is a reasonable argument for prompting on invalid user names, e.g. "This doesn't appear to be an existing account, make sure you typed it correctly, or try our [sign up page]".
Indeed, the assumption that usernames should be secret is stupid and senseless. Passwords are meant to be secret. Emails and usernames are not. Heck, emails would be public, were it not for spam issues.
Whether the username is sensitive depends a lot on context. If the service is a dating site, gambling, porn, etc. just disclosing someone is a user of the site breaches their privacy.
What this really highlights is a lack of consistency. If adding a security measure involves some kind of trade-off (UX in this case), you should really understand what you are trying to prevent and consider the rest of the attack surface. I think it would be a fallacy to immediately give up just because a larger vulnerability exists though.
That's sometimes true, but not always. Two examples: a signup may have a captcha, so the cost of filling out the form to check for an email address is high, or something like a bank sign up, which requires additional info besides the email address (account number, SSN).
Gmail allows you to use email+whatever. A lot of sites actually support this and this means it becomes significantly harder to determine what sites you use as each email+whatever is considered unique.
Which is an easily fixed flaw, when it comes to emails.
Usernames, yeah, you're not going to keep those private. But sometimes account names are not the same as display names, and display names can be duplicates, while account names should be reasonably protected.
How about just changing the signup process to "send us an email from your email address" and then you receive a reply with the further instructions/link? It would make it impossible to discover whether a user has signed up without gaining access to his/her email account. You could easily make this more abuse-resistant (and reduce the inevitable spam) by generating a temporary session ID and embedding it into the subject of the mailto: link, or even use temporary email addresses to receive registrtion requests.
The concerns about the denial of service attack, if an exponentially rising delay or similar lockout after a certain amount of login attempts are made, can be simply addressed by emailing an "unlock" email to the registered email address if a lockout takes place. That is, lock the account for 1/2 hours if there are a number of failed logins, but at the same time send an email that will allow logging in, by passing the lockout. Would this be a big security gap?
> 99.9% of websites on the Internet will only let you create one account for each email address. So if you want to see if an email address has an account, try signing up for a new account with the same email address.
That's terrible UX.
> But there's a tradeoff there between security and UX, I hear you say. I am trying to show you there is no tradeoff; you are choosing between a better user experience and a worse user experience.
I didn't reach this conclusion at all. Am I missing something?
Huh? He's suggesting that as a Real User that if you don't whether you have an account at all is to just sign up again. People use multiple emails for different accounts all of the time. How is that not a frustrating experience for the Real User?
An attacker who wants to find out of if the person with "example@example.com" has on account on your website, could try signing up with "example@example.com". If they get an error message, they know the person has an account on the website.
Your complaint is extremely unclear. Could you elaborate? Are you suggesting that websites should allow multiple accounts per email address as a matter of course?
No, my point is that signing up for a service (potentially) for a second time is a really frustrating experience. Why not push the user to reset their password?
>> I didn't reach this conclusion at all. Am I missing something?
He's saying that letting the user know the password is wrong, and not the email address, is a better error message. Since an attacker can simply try to register a new account to check if an account exists.
Silly rant... It would be more useful to explore why a service/site would like to 'hide' user names... and how it should be done.
If a site/service needs to hide user names then it needs to do a better job with signups. It's possible to hide user names / emails during signups too and say: "if you already have an account you'll get a reset password link otherwise welcome message from us".
I think this idea might blow a lot of A/B testing and conversion rates. People would have to check their e-mail address for actually creating their accounts, although e-mails are already obsolete for even activating the account ( You can just sign-up and sign-in later with your password you entered ).
May be behind this the author put some good deeds, but in the end I think it's overkill.
Unfortunately this assumes that there's no other way for an attacker to discover whether a username/email address is registered for a service. This assumption is incorrect.
No it doesn't. It assumes, correctly, that that involves a bunch of extra work and that obfuscation raises the economic cost of an attack.
Really!?! An attacker can just as easily write a script to check the password recovery form before attacking the login form.
You're taking something that is easy to automate and using it as a solution that makes it harder for people to use.
How many times have you been to a site you haven't used in a while to try several different passwords, only to hit the password reset form and discover the username wasn't even correct? How many minutes of your time were wasted? How much security was actually added?
You could put a captcha on your login screen once a user from an IP has failed more than N logins on a given IP address. You could also check for the existance of a cookie, and not allow logins that don't have it set.
There's lots of things you could do.. but displaying an obtuse error doesn't add to usability. I was talking about the password recovery screen, not the signing up.
The "you'll get an email..." is a message I've seen.. and had to deal with it being broken (the email provider the site used was overloaded/down) .. no email.. more broken usability...
> Also signing up usually involves more than a login/password (address, phone no., etc)
No. Using some features may involve more than a login/password, but even on most ecommerce site the signup itself is just a login and a password. Amazon needs a name (whatever), an email and a password. That's it.
I don't know if it's still the case, but for a long time at Amazon your account identifier was a combination of your email address and password. So you could have two accounts with the same email address and different passwords.
Needless to say, this caused some confusion for users.
If I remember correctly, revealing if an email address is already in the system is considered information disclosure vulnerability in OWASP tests, presumably because then you can do spear phishing against that email using the information that is subscribed to the service.
My applications can't be "signed up" for, you have to be manually added to get access because it protects sensitive information. In my case and all others like it, at least, this is not useless.
This is a good point for sites where the user can sign up on their own - doesn't necessarily apply to, say, banking sites, where you need to have an actual account to create an online one.
What sites should really say, is what dumb "password restrictions" they forced you to use on signup. For example sites should have a message that says:
"We are dumb enough to force your password to have at least one Uppercase/Lowercase/Number/Symbol and it must be at least 8 characters long, but you can't have consecutive numbers, this may make it different from your usual password pattern and force you to recover the password every goddam time you try to use our site".
This doesn't address timing attacks, which are why this is done in the first place. If the code checks only for a username existing and returns the error message, this takes a measurably different amount of time compared to then also looking up if the password matches.
The error shown isn't to dissuade people from using web pages to try to gain access to accounts - it's because the raw code itself doesn't know which is which, and writing code that does enables fast-paced timing attacks.
> This doesn't address timing attacks, which are why this is done in the first place.
This is not done because of timing attacks, it's done because of cargo-cultism and laziness.
> The error shown isn't to dissuade people from using web pages to try to gain access to accounts - it's because the raw code itself doesn't know which is which
Modern systems store passwords salted and hashed with KDFs. The stored hash must be retrieved before the provided password can be checked as you need the stored hash's work factor and salt, which are stored alongside (/as part of) the hash. Such a system necessarily knows which is which.
I might be missing what you're not following, but here's a quick explanation (and a reason why it's not a concern)
Correct username, correct password: takes 30ms to execute the code
Correct username, incorrect password: takes 15 ms to execute the code
Incorrect username: Takes 7 ms to execute the code.
You fuzz usernames, you get one that takes 15 ms, you know that's a valid username. You then start working the password.
Not necessary on most systems, because we're working at speeds that are measured in nanoseconds, and since we're using networks for many attacks, the delays are unpredictable and measured in (at least) milliseconds.
I understand how the timing attack works. I don't understand how it's a justification for hiding usernames. "You need to try to hide A because if you're not careful they can find A."
If anything the timing attacks weaken the argument against hiding usernames.
If you have an index on your "Email" field in the database, there may be discernible difference between the time taken to check the index and return '0 rows', vs getting a match and actually reading the appropriate data to build the result row.
I don't know if there's a solution to that in the general scheme of things, other than making the variance of query times between no user and some user as small as possible.
So? I'm advocating showing the correct error message... a timing attack is irrelevant in this case.
For that matter, adding a random 500-2000ms timer before returning a failed result would likely be as effective, and not lead to a bad user experience.
> This doesn't address timing attacks, which are why this is done in the first place. If the code checks only for a username existing and returns the error message, this takes a measurably different amount of time compared to then also looking up if the password matches.
Timing attacks are solved by how you implement the backend checking code and not how you present the result to the end user in the most user friendly manner.
It is, but with a sufficiently large number of attempts you can account for jitter. A good summary (with links to existing research) can be found here:
It's adding a few extra letters to a printed string and makes it slightly more obscure for attackers. Hardly a security measure, but it would be dumb not to do it. Can we move on and not argue about what a stupid error string should be? This is fucking ridiculous.
If I'm not logged into a site a that I regularly use, I'm probably not logged into my email, either. In order to log into my favorite site with Passwordless, I have to log into my email as well. With my password. One login for the price of two, and I'm still using a password.
Always send an email.
If that user already exists, make sure the email says "We noticed you're trying to sign up again. If you didn't do this, someone else is trying to sign up for you." If that user doesn't exist, send them the typical signup message.
The author has some great security tips in the "what should I do instead" but I don't think the instead portion is accurate. Keep private information private, and make access to public information as easy as it should be.
If emails are public, shoot, use a websocket connection to style the login field in real time and show the user whether or not the email they typed is valid.