Hacker News new | past | comments | ask | show | jobs | submit login
“Invalid username or password” is a useless security measure (inburke.com)
413 points by kevinburke on Dec 1, 2014 | hide | past | favorite | 182 comments



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.


Regarding rate limiting, must really suck to live in Qatar and be behind a proxy server with a single IP address with the whole rest of the country...



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.


The I, as new user, if I mistype my email, will just have filled whole form for nothing (and possibly just gave away my information to someone)


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.


Many people are paranoid about connecting Google/Facebook to anything. You will lose users if you don't give them a plain username/password option.


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.


I just default to Google since it's what I'd use for email verification if I were using email.


You can just use the email address as the username then.


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.

One possible solution to that particular problem: https://news.ycombinator.com/item?id=8683589

> 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.


>If the user has already signed up, send them a helpful "hey, you've already signed up" message in their inbox.

Well put. Im also a fan of 'If this wasn't you, click here' link within the email to more positively ID the request as malicious


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.


Thanks for this. I updated the post to add this as a possibility.

This adds more friction in the signup process than I'd be willing to accept, but it does solve the information disclosure problem.


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).


Sweet. As long as I get my cut. :-P

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.


If you're only giving the message when the username doesn't exist, wouldn't that mean the attacker would know when the username does exist?


The message is always sent through email though, so the attacker wouldn't see it.


> if emails should remain secret

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.


Hotmail used to do this and still does, so easy to find if an email is real.

Email is found, password is not correct. Email unknown.


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.'

:P


If they're stupid enough to allow non-unique usernames I wouldn't bet on getting a helpful answer like that :)


You do realize the helpful answer reveals another users username and password...


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.


Just because the requirement was remarkably dumb doesn't mean the developers that implemented it were.


I think Amazon used to do this back in the depths of time.


This seems like a messaging problem?

"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.


This reads to me like a more verbose version of "Incorrect username or password." I'd favour the shorter version that gets the same point across.


It's not the same, since his message indicates that the username does exist whereas your message does it.


"username or password incorrect" does not imply that the username was correct or incorrect. The system is saying one or both fields are incorrect.


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.


facebook handles this case by showing the profile picture of the user matching the email field.

banks and yahoo handle this case by showing a magic image that you chose, which also provides anti-phishing feedback


Telling them "correct password, wrong email" seems like a bit of an information leak if you ask me.

I think a "did you mean?" output in case of a bad password as long as there are lexically similar usernames in the database.


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.


Sorry, should have added a :-P to indicate my sarcasm.


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.


You'd be surprised... After removing the "type it twice" box during registration, the bounce rate of "welcome" emails went up quite a bit.


That's interesting. I always felt that repeating that field was a sort of faux validation, but maybe not!

Well, a lot of people do not know their own phone number.


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.


Just did that with a password the other day. At least I didn't mistype both my email and password when signing up...


But what happened to your conversion rate?


Well you can at least inform the user that the username is incorrect if there is no user by that name.


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.


Why is that an issue? You can also do that by trying to create accounts.


"You don't exist. Go away." is my personal favourite.


+1 Agreed. Always loved original user messages. Wish OSes were more funny in their alert messages.


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.


"is still the more correct and useful statement"

No, it is usually incorrect and it is much less helpful than identifying which is incorrect.

"it is entirely likely that the mistyped username is somebody else's valid username"

No, that's highly unlikely.

If the email isn't in the DB, just say so. If the password doesn't match, just say so.


> No, it is usually incorrect...

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.


Yes, you're correct that it's logically correct. I was responding more to "more useful" when it is obviously less useful.

It's unlikely that a typo'd email address is in the DB.


I agree with the article, furthermore here's another interesting reading from Mailchimp, as they reduced their failed logins by 70% telling users if the username or password was wrong: https://blog.mailchimp.com/social-login-buttons-arent-worth-...


>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.


Strictly speaking, keeping the existence of usernames secret does make brute forcing username/password combinations more difficult.


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.


However most sites reveal existence of an account before requiring a captcha, and many sites can't even fix this.

e.g. Twitter can't require captcha before letting me see twitter.com/username …but they're still doing this security theater.


Well, it's also perfectly fine to require a captcha after one or two failed attempts of login. What achieves the same goal.

(Altough, some real rate limiting is better, except when dealing with a distributed bot. Maybe both.)


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.


That will cost you dearly in terms of user retention.


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.


>> 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.

5.557 * 10^443 average Gregorian years.


Two thoughts:

* 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)


> Set no maximum password length (250+ characters)

It's important to note that if you take the classical advice to "use bcrypt" (http://codahale.com/how-to-safely-store-a-password/), your password will be effectively truncated at 72 characters.


Fair point. I'd still happily take 72 characters compared to what many sites currently offer. Anything over 30 is the exception not the rule.


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.


Is there a similar affect for scrypt?


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.


I never stated a disagreement with you or the article... I specifically stated that I agree with you on the topic.


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.


Even simpler than trying to sign up for a new account, many sites will tell you if you enter an unregistered email on their "forgot password" page.


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.


Yes, but that also alerts any valid account with an unexpected password reset.


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.


They should allow login by email instead of username


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 […]."

[0] https://tools.ietf.org/html/rfc7231#section-6.5.3 [1] https://tools.ietf.org/html/rfc7235


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 agree, neither issue is intractable.


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.

I was curious to see whether there is a way round this and a quick search threw up https://security.stackexchange.com/questions/40694/disclose-... - the top answer is quite informative.


There are privacy issues though. Take a known email address, run it through 100 sites, and find to find out what kind of sites the person uses.


The point of the article is that you already can do this very easily - just try to sign up to each site.


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?


> That's terrible UX.

I think the goal when the User is a malicious attacker is for them to have a terrible UX.


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?


That's not what is meant.

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.


> That's terrible UX.

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?

The answers are... Yes. Too much. None.


A lot of places have a captcha in their sign up process.

Also signing up usually involves more than a login/password (address, phone no., etc)

Yeah, someone could do something like "you'll get an email if this email wasn't registered already" on sign up


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.


Wouldn't that also make it impossible to change one's password?


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.


I was convinced until the main suggestion was to, "Consider throttling invalid login attempts by IP address or subnet."

The rest sounded okay but that seems to indicate that the author probably hasn't tried to solve the security problem on a busy site.


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.


It's not a security measure it's the truth. One or more of them is invalid, it's up to the user to decide what they meant to input.


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.


> This doesn't address timing attacks, which are why this is done in the first place.

I don't follow. Surely the reason to hide usernames is not to prevent a timing attack that would reveal... usernames.


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.


I don't see how what you say is really true in a system with properly hashed/salted passwords.

    SELECT "Id", "Hash", "Salt" FROM USERS WHERE "Email" = $input

    if (results.length == 0) return -1; //No record, bad user, return early...
    if (results["Hash"] != Hash(pwd.trim(), results["Salt"]) return -2; //invalid password


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.


And, if you're returning the correct error message, it doesn't matter.. the whole point of a timing attack is to determine the difference.

IMHO usability is more important. There are other ways to improve security. Rate limiting with < N failed attempts via an IP in under < X minutes.


Your code has precisely the timing attack he tried to describe in it. You're returning early when a user doesn't exist.


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.


That would make it an even worse pattern, your implementation leaking into your UI.


I feel like the variance in network latency is going to be an orders of magnitude larger than the extra time it takes to test a password.


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:

http://blog.astrumfutura.com/2010/10/nanosecond-scale-remote...


Doesn't matter.

Network latency variance just means you need to sample more. It doesn't prevent the attack.


So what, you're going to take a large number of samples for each username attempt?


I'd always wondered why no one seemed to notice this. I guess someone finally has.


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.


I agree with Kevin Burke's post. And I had designed my POC this way well before I read his post. https://lamba-todos.herokuapp.com/


Excellent point. However, I think username / password will be (at least partially) replaced by this:

https://passwordless.net/ - Token based authentication


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.




Consider applying for YC's W25 batch! Applications are open till Nov 12.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: