30

In my Spring application, I was planning to remove passwords from the authentication process by sending a "magic sign-in link" to a user's email address. However, in this question Rob Winch (lead of Spring Security) says the following:

Be careful that you know what you are doing in terms of allowing login from a link within an email. SMTP is not a secure protocol and so it is typically bad to rely on someone having an email as a form of authentication.

Is that really the case? If so, then how is sending a link for password reset any more secure? Isn't logging-in using a magic link the same thing as sending a magic link for resetting a password?

  • 5
    Good question, but I'd advise you to change the title, because most people (myself included) do not know what "magic sign-in links" are. – Tom K. Jan 15 '18 at 16:18
  • 8
    The difference is that a password reset link only works once. Yes, it does weaken password security considerably, but it's only valid for a short time and often asks the user to answer a password recovery question etc to limit the attack vector. – Bergi Jan 15 '18 at 18:36
  • Is this like how Craigslist does it? – Brad Jan 15 '18 at 19:33
  • You can ask your users for their PGP public key and encrypt all the communication. Facebook does. Then you can use the magic sign-in. (Even better, someone of the big trio had magic "reply to this email to post a comment" thing, which was the best usability ever.) – Oleg Lobachev Jan 15 '18 at 23:07
  • If the link can only be used once with a short expiry time and no info in the link can be used to derive secrets in the session it creates then you should be fine. Effectively, the link serves as an one-time password. – billc.cn Jan 16 '18 at 16:47
29

A magic link alone is not necessarily bad. A 512 bit entirely random value is going to be no easier to guess than a 512 bit private key. In general it is considered good practice to expire them after a reasonable amount of time. A good approach - which also avoids having to store database entries is to embed the token data in the url and sign it with a private key. I.e.

site.com/login?type=login&user=[username]&expires=[datetime]&sig=[signature of other parameters].

However email as a transmission mechanism isn't secure.

By default SMTP offers very little protection against interception. Traffic may be encrypted between servers but there are no guarantees. Even with encryption its still often possible to man in the middle the connection (encryption is not the same as authentication).

If so, then how is sending a link for password reset any more secure?

It isn't. This is why several services ask for some additional proof its you before sending the link (or after clicking it).

  • 2
    Even with encryption its still often possible to man in the middle the connection. When is that? Also, what about OP's main question - are sign-in links a bad practice, and if so, why? – Arminius Jan 15 '18 at 15:56
  • 7
    You have to store entries in the database anyway to make sure the key isn't used more than once. Since when is using a database something to avoid? – corsiKa Jan 15 '18 at 18:05
  • 2
    @corsiKa - you can achieve the same thing with a lastlogin value and storing an issue date in the token. If you implement this system using the user table you risk impatient users requesting a second code and them arriving out of order. If you have a separate table you end up with stale codes building up in the dB and expiring them requires special handling logic which can fail silently. The suggested method also protects you from sql injection. In practice it usually ends up cleaner to implement, more flexible and with less potential for bugs. – Hector Jan 15 '18 at 18:32
  • 1
    Sorry, I can't agree with you. If someone issues a second code, they should have two potential logins - one for each one they requested. Call me weird, but considering how cheap it is to store data, I'd rather keep around exactly what happened. And your last two sentences, to be frank, are not useful: if you're not sanitizing inputs for SQL injection, you're doomed anyway; how is it cleaner or less bug prone to use complicated encryption keys instead of a simple lookup table? And how is it more flexible to overwrite data instead of allowing multiple login tokens active at a time? – corsiKa Jan 15 '18 at 21:36
  • 1
    @Arminius Note the difference between end-to-end encryption and in-transit encryption. In the usual case, encrypted SMTP (SMTP over SSL/TLS) is in-transit encryption, meaning that the data is encrypted as it travels through the network from one SMTP server to the next. This is not completely secure as an attacker with access to one of the SMTP servers can read the unencrypted email, and it's always possible that the email might be relayed through an unencrypted connection at some point (I'm not aware of any standard to require encrypted SMTP for all relays that a message passes through). – Micheal Johnson Jan 15 '18 at 21:58
22

There are three problems here.

  1. As the documentation writes, email is not a secure protocol. Emails are stord in plaintext on the mailservers. The encryption between servers and between servers and clients is optional and beyond your control. And you are very likely not in a scenario where you can use any of the optional end-to-end encryption systems people built on top of email (PGP, S/MIME etc.). So you can not guarantee that nobody but the intended recipient will see the email in cleartext.
  2. Secrets do not belong into URLs. URLs appear in browser histories, in proxy caches, in server logs and many other places where you don't want secret information to appear.
  3. Users know how passwords work. It wasn't easy, but after a long struggle we finally got it into everyone's head that passwords must be kept secret. With your system, users might not be aware of what's the secret which is relevant for authenticating with your service. That makes them likely to mishandle that information and susceptible to social engineering attacks.

If you send links with a secret login token with email, then they should be single-use and expire rather quickly.

  • 1
    About the second point, if HTTPS is being used, then URLs don't appear, right? How different is that from sending a password in the body of a POST request? – Utku Jan 15 '18 at 16:32
  • 12
    @Utku HTTPS would rule out proxy caches, but not browser histories or your own server logs. Also, do you happen to have any 3rd party tracking scripts on your website? Google Analytics, perhaps? Those also log every URL, including GET-parameters, and store them in their database and use them for any purpose they see fit. So your URLs with token might end up in Google results. POST parameters are not inherently more secure, but usually don't get logged that much. But you can not make the user send a POST requests from an email, so this point is mood in your scenario. – Philipp Jan 15 '18 at 16:33
  • @Philipp - you'd usually use query parameters for this rather than using the variable as part of the URL directly. Depending on implementation you can also issue a cookie and retire the url token on use which mitigates your other points. Alternatively you could replace the URL before loading in external scripts. – Hector Jan 15 '18 at 17:27
  • 1
    I think the most important thing here is users - users may unitentionally share the link (for example, "Hey there's this awesome website, check it out [link]), it will end up in browser history,.. – JonasCz Jan 15 '18 at 17:36
  • 1
    @TeroLahtinen That's why with these kinds of links you are using the two precautions I mentioned in the last sentence. – Philipp Jan 15 '18 at 18:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.