169 comments

[ 3.0 ms ] story [ 251 ms ] thread
I like the dramatic style this opinion is written.
I could totally feel this blog post, not just read it.
Isn't the other reason so that adversaries can't tell if a particular username/email has signed up? This is not so useful for something like github, sure, but certainly is useful for the more embarrassing sites where users have an expectation the site won't leak their membership.

So in some ways I've always thought of this as a privacy concern rather than a security one?

Edit: I guess I'm thinking purely of emails where you don't get availability checkers during sign up.

As the post demonstrates, you simply go to the login form to validate the presence of accounts.

Few sites remember to anonymize that, which might be the real PSA: in such a case, if you require an email confirmation anyway, just send the "recover password" email internally, but let it look like the regular sign-up flow.

If you don't requite email confirmation, anonymous membership isn't possible (just try to sign up with that account, what is the site supposed to do that looks legit without giving away information?)

Even if this doesn’t increase security, you should still do it in the hope the user will check the username they’ve just typed as well as retyping the password.
Why? Why not just tell the user what is actually wrong?
Because the application doesn't know what is actually wrong. The error message is actually correct as written. The user entered their username incorrectly or their password incorrectly, or both. The application doesn’t know which and shouldn’t guess!
Why wouldn't the application know?
The application doesn't know if the username you entered is actually yours or someone else's.

You could provide the correct password to your account 'test', but not 'ttest'.

The server just tells you to check both instead, it's more semantically correct and offers some security improvements with user enumeration.

It knows if it doesn't exist though. This whole thing is about sites that say "Username or password is wrong" when they know the username is wrong because it doesn't exist!
Is it? I thought it was about sites that say "Username or password is wrong" when they know the username does exist! After all, the author is using his own, correct, username in the examples!
What if a username does exists, but isn't my username.

Imagine both 'dave' and 'davr' have an account. I'm 'dave', but I accidentally type 'davr' and my correct password. Now the site will tell me that my password is wrong. So I retype and retype my password over and over again and still can't log in, because the problem isn't the password like the error message says, but rather that I typed the wrong my username.

The message is still not wrong if you think of "or" as the boolean or, not as the boolean xor. The system knows the username is wrong but it doesn't know anything about the password.
It's not wrong, it's just not as helpful as it could be.
The application knows unless it some app written by someone who is starting with programming.
How can it? It passes the pair to some auth API and gets just a yes or a no back.
If the application already knows then the person using it is already authenticated.
If the username exists, how does the app know whether the user typed the wrong username or password?
This is true for existing user with wrong password, but that message would be wrong if the user doesn't exist. In this case, the error clearly would be the username, not the combination user+pass.
(comment deleted)
How can the pass be correct if the username isn't? A password is only correct in the context of a specific account.
The password may be correct for the user (who is a person, and has a password for that service).

Of course the person may have multiple user accounts and he may have given the "wrong" password for the "right" username account, but he may also have given the "right" password for the "wrong" username.

Because this prompts them to check the username again, instead of trying to enter their password again while they typo'd the username (but hit a valid account with their typo)?
Because it allows attackers to look for accounts. It's part of your privacy that I shouldn't be able to see if you have an account with sexycatpictures.com

Not accusing you BTW.

Read the article. It's debunking that exact argument.
You read the article. Author backtracks at the end.
I read it. He doesn't. Read it again.

> To prevent attackers from knowing whether an account exists or not your signup must only take an email address and provide no feedback in the UI if the sign up succeeded or not. Instead the user would receive an email saying they’re signed up. The only way an attacker would know if an account exists is if they had access to the target’s email.

> Barring that, “username or password incorrect” is just bullshit.

What he means is the only way it would make sense is if and only if a website's account registration page responding with something like:

"You tried to sign up for me@example.com. If that account didn't already exist, a registration email has been sent to it."

But nobody does that! Registration pages just say "Sorry that email is already in use", which is what makes this whole thing bullshit.

Assume a site has two accounts "user122" and "user123". When a user logs in with "user122" and a password and it does not work: What happened? Did the user mistype the password or the username?
Assume a user got their username or password wrong. What is more likely, they got their username wrong in a way that happens to be the same as another user, or they got their password wrong?
Most people store passwords in their browser, which already makes the answer not that obvious.

For a rarely used web site, I honestly would have no idea if I registered as bonzini, pbonzini or bonzinip. Now my surname isn't particularly common, but smithj and jsmith might be easily confused.

I have a commonish firstlast@gmail account and frequently receive what is the obvious result of people in various parts of the country incorrectly providing my email to apply for jobs, order pizzas, and use other services.

It is absolutely common for users to supply the incorrect username/email.

This is why it is common practice to require the user to enter their email address twice in forms.
Thank heavens we never invented copy and paste, would certainly make this more of an issue.
Apparently the set of users who don't know how to type their own email and the set who know how to use copy/paste are non-overlapping.
The article explains how to do it properly at the end:

> To prevent attackers from knowing whether an account exists or not your signup must only take an email address and provide no feedback in the UI if the sign up succeeded or not. Instead the user would receive an email saying they’re signed up.

Is this not also part of the various 'best practices'? (I confess I don't read too many of them!)

Typically, yes. This post didn't really offer any new insight to this. Maybe it's a PSA? Either way, it completely depends on the site's threat model. In the case of GitHub, it's quite useless because a user can just go to the targets's profile to see if it exists. Thus, it really isn't in GitHub's threat model, obviously.

Where it gets really interesting is when you perform user enumeration attacks via timing. IE: it takes the server a few milliseconds longer to send a registration email than to not, or it takes the server longer to try to validate a password hash than to lookup a nonexistent user.

Is this possible to detect despite external factors (variable latency etc)?
It's black magic to me, but I'm paranoid about timing attacks after seeing a few examples in the past of what's possible for a clever attacker to guess if they can gather data from a number of requests.
I've once tried to sign up for some site (I can't remember which) which went through with the usual successful signup, please check your email text. The email I received however was something along the lines of 'you already have an account with this email!', which seems like the best way of doing things.
100% agreed.
It's still good advice for software where there is no public signup, such as SaaS where accounts are created by administrators.
> Even if reCAPTCHA was perfect, a hacker could manually validate their usernames of interest by trying to sign up, then automate an attack on the sign in page.

Why is imperfect reCAPTCHA worthless? Do sign up pages even allow brute forcing of usernames (once validated)?

Is he suggesting to fix sign up pages, or to allow brute forcing usernames on login?

His writing style is dramatic, but the arguments are very weak.

The solution is relatively simple.

1. Email and password for login. Don't tell the attacker which is correct.

2. Email and password for registration. On registration send confirmation email. If user is already register attacker would need access to their email. Access to email is game over.

So now an attacker can't see which users are registered with your service and you've protected your customers privacy.

Extra points if your code is aware of timing attacks.

Sure but everyone does 1, and not 2, so it's bullshit. Also what is a bigger annoyance? People can slowly use emails to look up if you have an account on a website, or it being a pain in the arse to log in?

Except on some sites, e.g. dating websites, this is a stupid theoretical security gain that just pisses everyone off. Like requiring numbers in passwords (basically everyone adds a 1 at the end) or making you change passwords frequently.

> 2. Email and password for registration. On registration send confirmation email.

This opens up a different problem. It should be:

2. Email only for tentative registration. On tentative registration, send confirmation email.

3. User clicks link in confirmation email, which takes to page for setting password. (Alternatively, confirmation email includes randomly generated initial password, user is required to change it on first login). After password is set, registration changes from tentative to confirmed.

If email and password are both included on the initial registration form, an attacker can try to sign up people and some fraction of those people will accidentally click the link in the confirmation email, thereby resulting in some new accounts where the attacker knows the email and password, and the email owner does not know the password.

You should definitively set the password after clicking the link. That said, what would an attacker do with that account?
Suppose it were a social media site. Now that attacker has a working account with someone else's email address, and that email address is considered verified by the site.

The attacker could then use that account to post threats, harass people, and so on. If he goes far enough that either law enforcement wants to come after him or someone wants to sue him and the site is served with a warrant to reveal information about the poster what they are going to cough up is the verified email address of the account holder.

That will be followed to the email provider, and from there to the email address holder. The email holder's claims that he never made the social media account are going to sound unconvincing--he clicked the confirm link to make the account!

Remember, a civil suit only requires a preponderance of the evidence, not proof beyond a reasonable doubt. That verified email might be enough to reach that standard.

In a criminal case it would not be enough...but if the matter was serious enough it might be enough to justify a warrant to search the email address owner's place and computer. At the very least that would be very annoying, and at the worst it could uncover things that the email holder does not want brought to law enforcement attention.

And all of this activity on the site happens without the site ever sending a single other email besides the account verification, that would tip-off the victim?

Color me unconvinced.

I feel like my job is to never trust anyone. Don't trust their string encodings, the characters they put into those strings, the arrangements of the characters we do allow, etc.
So, as per the author, sites should first check if the user exists and then check the password? Why? What if the username belongs to someone else?
Signup and login should behave the same, and provide no information wether the email is registered or not. And username should be treated as public.

So for login: always say "email or password is incorrect".

And for register: as he said, always say "we sent you an email to verify your email".

Except that when you are signing up, unless the service is using some draconian password formatting rules, any "email or password is incorrect" error can be inferred as the email is incorrect, and if the email format is correct, it's must likely because the email was taken.

"email or password is incorrect" is bullshit is right.

Can you please give an example? I don't think I understand what you're saying.
Either you or I misunderstood GP. I understood it as if (as long as any email format validation allows the address) the service only outputs "sent you an email for confirmation", even if the email is registered. The attacker wouldn't know if it was the first time or the 50th time that message had been shown, as it's always the same.
Correct. The UI message would always be the same, some variant of "email sent." Even if the account already existed and it wasn't actually a successful sign up of a new account.
I understand him perfectly, what I'm saying is what he's proposing is useless, because you can mold your email and password into anything that you know for certain it will pass validation, that's your oracle right there. During sign up, if you know both the formatting rules of what you typed as the email and the password cannot have caused an error, then it follows any error message (500 errors notwithstanding) must be a duplicate email. Because that's typically the only constraint difference exists between an email and a password.

Given that, who cares what error message you display, as an attacker I only need to be able to find out weather a system has an email or not, and the sign up screen is a perfect oracle.

Precisely this. The title of this article should probably be renamed because it's looking at specific examples where the whole process (ie login + registration flows) hasn't been implemented properly.
Edge case: For services which uses an additional account name/alias (separate from email), where you can login with either account name or email; An attacker could find a target account name through signup, using an email the attacker owns.
True.

For this I would recommend adding the mention "your username will be publicly visible" during the registration process.

Why? I don't see why it's important to hide existence of a user unless you're allowing people to try multiple logins per second on your site. (I'm not an expert so I am sincerely asking to help me understand.)
If your users want to disclose that information, provide them a way to make a public profile if they want to, and if it makes sense. Don't assume their intentions. They might have good reasons you didn't think of.
For some websites, people might not want others to be able to find out whether they have registered if they only know their email address (e.g. same kind of websites for which the incognito/private mode exists in browsers).
You are leaking the information. Maybe you want to check if your buddy is a registered on some controversial site, or maybe you want to target someone for hacking…
We're used to assuming that the attacker knows a login and is guessing at a password, however the opposite scenario is is increasingly common.

Suppose another website has a security breach, revealing many names and passwords. User John Doe used a password of "foo", so an attacker starts trying combinations like jdoe/foo or johnd/foo or john_doe/foo, looking for the same person reusing a password on your site.

By denying them information about which login names exist, it's harder for the attacker to either zero-in on the correct username (and try alternate password variations) or to be certain that they've got nothing and that it's time to move on.

I could find user 'bo1024' has an account on pornhub - not necessarily you and you might not care but certain situations it may be a problem.

You could argue it's security through obscurity - I'd say preventing leaking data.

Very quick examples, if I can check if an email address is registered on a site I can

1. Identify people who are gay/bi (e.g. signed up to grindr)

2. Identify political affiliations (depending on site)

3. Identify health issues (signed up to a mental health forum, or cancer support group, etc)

These things people might be happy others knowing, but I hope you can at least see some cases where you might not.

You could also potentially build spam email lists too, to target users of that web site, if you automated some system that guessed emails addresses and filed away the ones that come back as registered.
Disclosing the existence of a user increases the success rate of certain attacks.

Say I've got a leaked password database for foo.com and know that the user bob@gmail.com uses the password "tomato1". If I try using his credentials to log into bar.com and get the message "username or password is incorrect", I'm just going to try the next user on the list. If I get the message "incorrect password", it makes sense for me to try "tomato2", "tomato3" etc. If I know that your password policy requires eight characters and a capital letter, I'm going to try "Tomato11". This is obviously trivial to automate.

You can't protect your users against credential-stuffing attacks if they use the same password everywhere, but you can offer them a small layer of protection if they use the same password with minor variations.

As others have pointed out, mere disclosure of the existence of an account could be a serious privacy breach in itself.

Any evidence of this being used in the wild, particularly where the attack is only trying password variants if the initial failure indicated the user exists? Not disagreeing with the point, just would be interesting if anyone's seen such an attack.
Just replying to my own post to say thanks everyone who replied (can't edit the original anymore), I learned and got some good food for thought.
If you have a user name, why do you care about e-mail? Let people enter an arbitrary user name, and log in with that. Username enumeration doesn't carry privacy concerns since users can ensure their usernames don't reveal personal information. For duplicate e-mails on signup, who cares? Since you're not using them as an identifier, let multiple users have the same e-mail address.

Making your validation errors cross mediums and a wait for an e-mail to delivered is an unnecessarily hostile user experience.

I think you have a good point in that if you are going to use usernames as an identifier, there is an argument that having an email also be an identifier is sort of redundant.

One problem with that is that when users are given the option of an arbitrary username, they tend to be much more likely to forget that username than they are the email address they use daily. So, you need some way of resetting their password and letting the user recover their username. In some cases, you could pair that with other identifiers, like their name, phone, social security number, etc. However, then you are just trading the email as an identifier for something else, which you would also need to check during registration.

For this reason, I've found that moving away from a username and just relying on an email for a login makes managing multi-user sites a great deal easier from an admin side.

That's fine though, sending a forgot username / password e-mail is much simpler to do without exposing the fact that you know their e-mail (just send a "sorry, we don't have that e-mail on file" to the e-mail address if there's no match)

I agree that e-mail makes for a better login experience, but if exposing who uses your site is too much of a privacy concern, I'd rather move to usernames than have to implement awkward user experiences to never reveal whether someone is a user or not.

I think a lot of sites already do that, although they may not send an email saying 'sorry, we don't have that e-mail on file,' it is pretty common to get a 'if that email exists, we have sent a reset e-mail to it' message when you do a password reset that doesn't expose if the email exists in the system.

Although to the point of this article, they will then happily tell you you can't use an email during signup, so it is a mixed-bag.

I suppose if you allowed multiple usernames per email, you could just email them all the usernames that they have on that email address when they forgot their username, but that seems like a clunky setup. It probably depends a lot on the service though, as someone posted a link to a discussion from 2014 about Amazon's reasoning for allowing multiple emails elsewhere in this thread, which makes a bit of sense for their use-case.

I have an argument for "username or password is incorrect" messages: it's possible that the password is correct, username exists but isn't the intended one. Then "password is incorrect" message would be lying, as the issue is actually with a username.
Optimizing for the common case seems prudent here.
"password is incorrect" would be technically correct, perhaps not as helpful as it could be, but certainly not "lying".
You mean you log onto John with password 12345 and the website says "Some other user uses this password, but not John"?

Seems wrong, somehow.

If you, as a developer, are technically able to check that the password is used by another user, you have failed pretty big at best practices.
Yeah, that too :)
Doing it every time a user login failed is probably infeasible if you have even a moderate number of users, but you can presumably do it on an ad hoc basis unless you have a ton of users. Or am I missing something?
Yes you are. If you have done your security right, users' passwords are not stored in a form that lets you determine whether one is equal to another.
It's a little different from determining if one salted hashed password is the same as another salted hashed password. Whether it's account signup ("the password is already in use") or login ("you typed in someone else's password"), you have the plaintext of the password, and can just loop through the user table and attempt a login for every user with that password. It's slow when you have a lot of users, as mnarayan01 mentioned, but certainly reasonable as an ad-hoc thing.

(Not that any of this is good practice.)

That's so horrible it never entered my mind. But you're right, of course, one could do that.
You might be able to do it for all user names within a certain Levenshtein distance of the current user. That would handle mistyping, but it wouldn't handle the case where you have numerous emails and forgot which you signed up with on this site.
If you are able to do that, then I insist: you probably have failed at best practices.

Most likely on this part: a good password hashing (ie. security hashing) should be fast so that you can log-in but slow enough to prevent brute force (ie. what you are implying). Hashings like md5/shaX don't have that: you can compute of lot them very quickly, which is their purpose. Bcrypt/Argon2/... will have a cost/time that will allow only a few computation per second, which is their purpose.

So if you did best practices well, and try to loop through your users database, (I assume you have more than a few hundreds users) it might take some time, some long time. Anyway, you'll then fail at another best practice because the initial user trying to log in will get bored and be gone somewhere else ;-)

More like, I log in as john with password 12345, but I forgot that I had to sign up as john87, so the password is correct and saying it isn't is misleading (even though the system doesn't know that for a fact, it is a possibility).
But how would the system know you're supposed to log in as john87? It would have to check your password against ALL passwords (which shouldn't be technically possible in the first place, because passwords should be hashed and salted, and the only way to check if they are valid should be in context of the given user - as gregoriol noticed).
It doesn't, so it doesn't know whether your password is incorrect, so if it claims it is incorrect it is saying something it doesn't know for sure.

Also it's technically possible to check the password against all other passwords, it just requires rehashing it for every user in the table, you shouldn't do it obviously.

edit: Even if you would check it, it wouldn't help to answer the question about whether the password or the username is wrong, even if the password is used for a different username you still don't know that it's the right password. So it's a bit strange that it is brought up as an issue that you can't check against other usernames.

This is a better argument, but rarely given. The issue is the accepted argument made for 'username or password is incorrect' is it's a best practice protecting the existence of accounts on sign ins, yet sign ups are ignored.
If the username is used as the salt when storing the hashed password in the database, it's unpossible to know if a supplied password is valid-but-for-a-different-account.
Wow, using the user as the salt is awesome. Is this considered an ok security practice?
Nah, user logins/emails often won't be long enough or random enough. See https://security.stackexchange.com/a/8024/28881 and https://stackoverflow.com/a/5565071/2521092
Would it be an okay practice to prepend the username as extra salt, still using the randomly generated salt?
No, the hashed passwords will be way too salty and will throw off the flavor of the app
Why not just use a longer salt? The username is only going to reduce randomness. Moreover, I don't buy the presumed advantage: nobody is really parsing that message to mean someone else could have the same password.
Be careful about how you merge the username and the random salt.
Why would anyone use that ? Best practices require that every user has a random (probablistically) unique salt. Just use bcrypt, or other password hash functions.
(comment deleted)
Agree, the pair username, password can be invalid for 2 reasons:

It is the intended user, but the password is wrong

It is the right password, but the user is mistyped

The login screen has no way to know when is one or the other.

The OP wrote a whole article based on the wrong assumption, and since the title is a click bait, it made it to the front page of hacker news.

Sad.

I think you're confusing "correct" and "exists" or "was entered deliberately." A password can only be correct or not for a given account. If the password differs from the one recorded for the user you specified, it is incorrect. It doesn't matter if there's some other place where that password does exist.

A system that used an "existence" or "user intended to type this" concept of password correctness would be either unimplementable or insecure to the point of uselessness.

If that is the justification, then the possible error responses could be: 1. Username is incorrect, or 2: Username or password is incorrect. If no user exists with that username, then you can just tell the user that the username is incorrect.
(comment deleted)
The title is "bullshit". The real problem is that they leak the information they try not to leak anyway, on a different form. This is a common, but not universal, problem.

It's not OK to leak information, even if that information is maybe leaked somewhere else already.

In the GitHub case the handles are public information. Anyone can go to https://github.com/<handle> to verify if it exists. So they trade off usability of a clear error message for no gain at all.
This is true for the username but it's possible to make your email address private on GitHub in which case the message that your email is taken can still be considered an information leak.
But to you -- the user entering credentials -- that error message is still accurate. From GitHub's perspective, they don't know which one you entered correctly. It could be argued they should tell you that the username doesn't exist if it doesn't (reasonable with public profile), but in the case of an existing user, this is the only correct error message.
Not quite on topic, but it would be nice if more websites would offer the option of using client side TLS certificate "login" with or without an additional prompt for a username and password.

It would be next to impossible for an attacker to bypass that. For example, even if the attacker provided the correct credentials, they most likely would not have the associated client-side TLS certificate private key. Then the server could just reject the log on attempt outright (since the certificate wasn't provided or verified).

Sounds like a great solution - would browsers need to support it? Do you have any resources on implementing it?
Already supported by browsers. Massive PITA to use. The old Startcom SSL webapp was an example.

Private keys and certs aren't as portable as passwords. Backing them up, copying them to another device, etc. lacks good UI.

Browsers has supported it since the late nineties. The problem are on the practical side. If you ever log in from more than one machine, all must have your private key, and the mechanism for synchronising keys between machines are not there. You have to manually install your key each place. It has also been too hard for most people to make and handle public/private key pairs. Also, if you don't have the private key with you, there is no way you can log in to the site. All of these problem and many other usability problems would have to be solved for client side certificates to be a success.
Chrome already syncs data between platforms. Seems reasonably straightforward to include client certs in that data.
> If you ever log in from more than one machine, all must have your private key, and the mechanism for synchronising keys between machines are not there.

I don't think that's good practice. What's better is to have a separate key/certificate per device that's used to access a service. That way, even if one machine is compromised (or stolen), then the user can still use other devices to log in. Also, the service provider can disable certificate log in on a per device rather than a per account basis.

> Also, if you don't have the private key with you, there is no way you can log in to the site.

That's not necessarily true. Some HTTP server software (e.g., nginx) do have the option of requesting/asking for a TLS client certificate rather than requiring one. If one is not provided, then it's still possible to connect and log in. Server side policy can be much more strict in terms of locking the account in case of incorrect credentials or restricting access to certain account features if the client certificate wasn't provided.

This is how web auth was supposed to work. It turned out to be too hard to deploy outside of enterprises.

U2F is the modern re-do of client certs.

U2F does that. I wonder if sites could use the U2F token as the first factor and ask you to enter a password as the second factor (along with a "remember this computer" box for the password). Would make things much more convenient (unless you were on a device that didn't support U2F, I guess).
It also seems that would help with not giving out passwords to spoofing sites
The spoofing site could just pretend your U2F was valid and get your password, although it couldn't really do anything with it anyway.
The spoofing site wouldn't/shouldn't be able to pass the browser validation of the TLS server side certificate.
Why not? How hard is it to get a cert for a domain that looks like paypal-businesscenter.com?
Moreover, the browser could remember the expected shared secret based on its and the server's RSA exchange.
Ask HN: Why does Amazon allow multiple accounts with the same email address? (2014) | https://news.ycombinator.com/item?id=7075372
Interesting. Just reading this now, but it makes me wonder, what happens if you set two accounts to the same password?
> you can create two accounts with the same e-mail address, but you will get into trouble if you try and give them the same password. I'm not sure what happens, so try it and see.
I've somehow ended up with three Amazon accounts under the same email address. Two on Amazon UK (which appear to be shared with Amazon US and Amazon DE), and then a third on Amazon JP (which only appears to work there). Very confusing at times (I've ended up putting a deliberate misspelling in my name -- Stpehen instead of Stephen -- so I can tell at a glance which account I'm on).
There's definitely a trend away from this to some degree lately, I feel. It's probably more influenced by Google not doing it with their accounts (enter username -> forwarded to password page with your avatar) more than anything else, mind.
The right answer isn't a blanket "sites should do this super-secret e-mail-only shuffle and not tell you anything".

First, you should define your threat model: which information is considered secret and which isn't, and treat any violations as security vulnerabilities.

If usernames are public by design, then don't hide them in one form, and expose in URLs elsewhere on the site.

If exposing who's registered on your site really is a threat, then by all means have a weird registration (and password reminder) that doesn't tell whether it worked or not. But if your site is for cookie receipies and you don't consider exposing who's a fan of cookies a privacy violation, then just use most helpful messages you can.

default to privacy though, please
Not really. "Default to privacy" is what gives you insane useless UXes like the one in the article, where you're making login (already a frustrating experience) more painful with absolutely zero gain in security.

Default to knowing your threat model. Default to balancing security concerns with UX, and make an informed decision instead of blindly following best practices.

I don’t want others to know all of the places where I have accounts.

That’s an easy way to be targeted.

That's the point of the article though - for a large percentage of services, if you know the username/email address you are targeting, you can just try to register them and see if it works. Obfuscating the login process makes little difference.
Which is why they shouldn't leak this information on the registration page... Instead they should pretend the registration always succeeds and then disallow login until the email has been verified.
Which is back to bad UX.
That works for the email, but not the user name. Going through the entire process and then telling the new user "That one's already taken, please start over" is not going to make people happy.
The point is that sites generally leak this anyway via signup. With github it's even easier, e.g. https://github.com/someuser -- I looked through my settings and their doesn't appear to be any way to "be invisible", though I could be missing something. When you can do a simple query like that, sacrificing UI at sign-in seems totally pointless.
You're missing the point. Fix the signup form instead of just giving up.
I'm not sure the point made was as much "use this blanket solution" as "if you're aiming to do this, go all the way".

Obviously, Github and Stripe aren't actually enforcing these messages as part of some larger security policy, or if they are, they're doing it very poorly. But if they were, the email shuffle is what they ought to be doing.

You got it. You can be about security or UX. And when the accounts are public I'm especially in favor of taking advantage UX-wise. The issue's when both are half-assed.
Right, for example if you run an email service, your usernames (addresses) should be hidden. That's because a spammer could use your login page to find valid usernames and then send spam to them. They don't have to guess passwords to cause damage.
They could also use your signup page to attempt to create an account for user@example.com. Since you can't allow duplicates that rejection gives them the same information.

Might as well let a user logging in that the username is incorrect to make the legit use case, i.e. user has a typo and/or misremembers their username, more pleasant.

I usually suggest clearing the username field on failed logins as well. That way if there is a typo, the user doesn't try it again thinking only the password is wrong.

Or just use the SMTP specification and or bounce-backs to do the same...
The other right answer is do not let someone create an account with an email they don't have access to.

My short gmail address gets a signup on some random website a couple times a month and they're often nigh unto impossible to delete.

Fitbit is one of the worst for this.

oh yes, i get french people ordering cabs from paris.
I think there is an important point which is ignored, in the article and here in the thread: typos.

Unfortunately, when designing a login flow (and a signup one), you can’t assume that the user always inputs the right things.

Try logging in into facebook, for example, mistyping gmail or with your password with the wrong case, like all uppercase. In many cases... you get in! This is to prove that they had to “improve” their flow to account for wrong user input.

Because user input can be wrong in both email or password, the error message should account for both.

A lot of places separate out the email/username field so it's a 2-step form. They will show you your avatar and maybe some other public info when you enter the password. This is a better way to do this I believe, although it does make logging in with a password manager [slightly] more annoying.
This is often done to support SAML or other federated sign in
I take issue with your cookie site example, because the user of the cookie site is probably using the same credentials on an important, sensitive site.
This is actually a feature for users who have almost the same username and mistype this instead the password. E.g. this could probably happen through an unfamilar kayboard layout.

I understand that a lot of people think this is a security feature, but once upon a time it was the lazy programmers answer when "SELECT * FROM users WHERE username=? AND password=?" didn't return a result.

With proper salts for hashed passwords you now have to find the username, use the salt to hash the password and compare this. If your database allows to hash passwords with a dedicated function it's still the easiest to say username OR password must be wrong.

After reading this I went straight to change the login system I'm currently working on ... And discover that I would need to add some extra code paths / conditionals ... So for me it's not "best practice", it's more todo with laziness and not wanting to add complexity to critical functions.
Doesnt “username or password is incorrect” falls into the Security through obscurity category?
... also, you can often do "Forgot my password" and if you give unregistered email it will tell you that.
In the article: "You gain no security, yet your customers lose clarity."

Oh boohoo. Like it's not on the customers side to know which email it is and which password.

And as many have said, one does gain privacy.

Here is a super useful article about how you should build login https://blog.codinghorror.com/the-god-login/ (if you don't want to rely on professionals from Auth0 or Okta :-). In the article, there is a very good statement "being user friendly is way more important than being secure" and this is exactly this case also...
Lately I've seen the catch-all "We could not verify the credentials you entered" and it has grown on me a lot.