26

It seems common practice, when denying access to a user because of an incorrect email / password combination, to not specify which of the username or password was incorrect. This avoids leaking the information that an account does or doesn't exist with that email address.

For instance, if I try to log in with my spouse's email address on a dating website, and the error message is "Incorrect password" rather than "There is no account with this email address", I can draw the necessary conclusions.

But how do I avoid that same information leak on an account creation form, where I must prevent a user from creating an account with an email adress that already has one?

foucdeg
  • 403
  • 4
  • 10
  • 2
    I wonder if I'm missing something here, but I never understood why sites want to "protect" this kind of leaking. If I really want to know if an account exists for that email address, I can simply try to register a new account with it... the website will not allow me to proceed if it already exists. – Nuno Jul 17 '20 at 07:43
  • 4
    @Nuno, as you said, websites usually *don't* try to protect this. But in some cases, it might be worth thinking about it, for example for services that people might not want to be publicly associated with (political stuff, sexual stuff, etc.). The OP is asking for possible ways to protect privacy in such cases. – reed Jul 17 '20 at 07:57
  • I did see some sites saying something like "if an account exists, you will receive an email for password reset" and I, as a user, get confused whether I have signed up in the past or not... and if the email doesn't arrive, I wonder if it's because I never signed up before, or my ISP blocking that email. To me, this protects nothing and is just bad UX. – Nuno Jul 17 '20 at 08:25
  • 1
    This looks like a duplicate of [Preventing User Enumeration on Registration Page](https://security.stackexchange.com/questions/69370/preventing-user-enumeration-on-registration-page) – James_pic Jul 17 '20 at 11:58

4 Answers4

57

I'm probably stupid and don't understand the issue, but to me it looks like the problem can easily be avoided by providing the necessary information only via email (which an attacker isn't supposed to be able to access). If you don't want to leak any information, then the public messages must not be distinguishable, whether an email is already been used or not. If you really want to be careful, technically, you should also make sure that the response time is the same, to avoid timing attacks. But this, depending on your needs, might be overkill.

So what happens is:

  • If the email has not been used yet, you display a message like "Thanks for registering, now go check your email to complete the process". The email will contain a link to validate the address, and when the user clicks it the account will be created and enabled. You can also create the account at once, before validation, but you will need to make sure an attacker cannot check if it's been created or not (otherwise that's information that is leaking).

  • If the email has already been used, then you display the same message (see the point above), for example "Thanks for registering, now go check your email to complete the process". This way an attacker will not gain any additional information. Is the email address already been used or not? The attacker can't know, unless they can read the email. But the user will know, because the message you will send via email this time is different, and it might be like: "You just tried registering at example.com with this email address, but you already have an account connected to this email address. Did you forget the password? Blah blah blah. If it wasn't you, just discard this mesage".

As a result, an attacker will not be able to understand if an account has been registered with a specific email address, unless they have access to that email address. A user, instead, since they supposedly have access to the email address, will be able to get all the information they need, whether they signed up correctly or they tried to sign up twice.

reed
  • 15,398
  • 6
  • 43
  • 64
  • 5
    I'm probably stupid, too, as I was thinking exactly the same. +1 – Esa Jokinen Jul 16 '20 at 20:51
  • 1
    None of you are stupid, and neither am I, because that is roughly the solution I proposed in my self-answer. I'm just surprised that I don't see many websites doing this, which is why I wanted feedback on it. Thanks! – foucdeg Jul 17 '20 at 12:51
5

An idea I have: on the creation form, only ask for an email address. Upon submission, immediately send an email to that address, including a link to a page which allows the user to choose / reset their password.

On the page, display a message like "An email has been sent to your address in order to verify your account or reset your password."

First password choice and password reset are essentially the same thing, and verifying the email address is necessary anyway.

foucdeg
  • 403
  • 4
  • 10
  • 2
    This can be a huge user experience barrier. I get what you are trying to do, but this can create a usability problem. The better option is not to have the email address be the username. – schroeder Jul 16 '20 at 13:01
  • 1
    @schroeder I don't see what this has to do with a username, unless you're suggesting that accounts *not* have associated email addresses. Or if you're suggesting that any specified email address not be verified (which has its own problems), that barrier would already exist, just later in the account creation process. Arguably forcing people to invest more time in setting up their account first encourages them to go through the barrier. – jamesdlin Jul 17 '20 at 08:34
  • "when denying access to a user because of an incorrect email / password combination" and "if I try to log in with my spouse's email address on a dating website" -- you are using the email as the username. Your base case problem only exists if you use the email as a username. If you don't, then the situation is simple and you do what everyone else does: just send the email to the address. If the account authentication is not tied to the email, why have a UI element to inform the user? – schroeder Jul 17 '20 at 08:47
  • @schroeder The OP's question wasn't about the login form but about the account creation form. To me, his solution seems pretty similar to reed's answer. Is there something I'm missing? – nobody Jul 17 '20 at 09:59
  • @nobody because, like reed, I cannot see a problem to be fixed. The only way there would be a problem is if the email was the username, as is the situation in the provided context. The problem, as stated, is whether or not to inform the user in account creation that the submitted email was already is use. The answer is simple: "don't". Why would you? If the email is not the username, then we might be missing some important context. – schroeder Jul 17 '20 at 10:05
5

This is a bigger question then it might seem. I'll try an focus on the privacy aspect, rather then the engineering aspect.

This scenario isn't entirely implausible, given the Ashley Madison leaks, and the repercussions individuals and/or companies received.

The core issues here are:

  1. How do I provide a secure experience, without some semi-unique publicly identifiable information?
  2. Can I offer users some level of plausible deniability?
  3. In the very likely scenario of password recovery, how do I handle this with some level of privacy?

For the purposes of this question, I will continue with the understanding that we are:

  • Attempting to mitigate casual or widespread "outing"
  • Preventing the linking of user information to a real human being

The difficult part is that an account by nature usually needs to be unique, and tied to someone. Additionally, it needs to be secured with something like a password to keep conversations private ("something you know").

To add some additional protection, allow only those WITH an account to query for other users. All services and functionality are hidden behind a login screen. How you decide to implement registration is a separate issue. This idea is implemented on several services already, but it is unclear how effective it is. You would also have to avoid listing account creation date/time anywhere. This satisfies points 2 and 3, without dealing with 1.

Easiest thing would be to force a user not to use a public email service or phone number. Again, how this is implemented is a software engineering question. You will have to deal with bots or users who wish to abuse the platform. This satisfies points 1 and 3, unlikely 2 as well.

Taking an idea from how apps/users work in censorship central China, assign each user a "random" ID. These could be 8-12 digits long so they are both unique enough but also rememberable. Having a copy of this ID anywhere besides the user's brain and the database can enable linking the two, defeating any privacy gained. This means no emails, no phone calls, no "selfies", or anything of the sorts. Users can assign themselves a public facing name when changed by the user at any time, points to a generic "doesn't exist" page.

Steam Client preview for Chinese market showing numerical only user names

To gain some level of plausible deniability, you can have a "no sign up" process. Users could have multiple accounts tied to an email address or phone number without a verification process in place. Each time someone wishes to "register", a random ID is assigned and only displayed once. From there on to access that account, you provide the "secret" ID and a password. The system will let you register a set number of accounts per an email address or phone number, but more than the usual 1 to 1 mapping. These last two paragraphs satisfy points 1 and 2, but not 3.

dark_st3alth
  • 3,052
  • 8
  • 23
0

This is a very good question. In my opinion we need to clarify what you use in order to identify a user. Is it an email address, a username that the user selects or a username you give to your user. Each of the above must be handled differently. If you use as email as account identification then the data leak is a lot more important. Remember email is considered sensitive data. This could result in your application leaking the email address from users. If a username is used then the leak is not that important in my opinion as the user usually uses an alias that is not considered sensitive data and there is no real privacy issue.

Having said that the problem still exist if in the registration process you inform the attacker that An account already exist with this username you give the attacker a small hint, that his efforts to fish or brute force the password of the user is not for nothing.

So what can we do?
My personal suggestion is to require 3 fields username, email, password .Both the username and email address should be unique. Which means there cannot be the same username more than one time in the database. Same for the email. This way you can have a only one user using the username = bill and the only a user with email=bill@some_domain.com

  • Examples
    Let's say there already exists a user with the following credentials.
    Username=bill + email= bill@some_domain.com
    The bellow combinations should all be invalid.
  1. Username=other_username + email= bill@some_domain.com
    • Message --> username or email invalid
  2. Username=bill + email= other_user@some_domain.com
    • Message --> username or email invalid
  3. Username=bill + email= bill@some_domain.com
    • Message --> username or email invalid

When the user will try to login only one of the 2 values should be enough to enter + the password. In your database the username filed could look something like this: system_username = username+email for example: system_username = bill,bill@some_domain.com * (This could result in performance issues)

  • How to mitigate If it's to much trouble or more the current schema of the database does not allow for such a change, then apply the same principals ass on the login part.
  1. Let some time pass before the registration will complete. (Brute force will take more time)
  2. Limit the create account requests . And more..

(Edit: As pointed out by nobody in a comment bellow, there is a problem with this solution when a big random username is entered.)

  • 6
    In your scheme, if I wanted to determine whether an account existed for `example@domain.com` or not, I could simply try `example@domain.com` and a long random username. Since there is a very low chance for someone to have used the exact random username I chose, if registration fails, I can know almost certainly that an account for `example@domain.com` exists – nobody Jul 16 '20 at 16:33
  • Well, that's a valid point.I didn't think of that. In other words this solution does little to nothing. :( – Vasilis Konstantinou Jul 16 '20 at 16:52