37

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?

Hector
  • 10,893
  • 3
  • 41
  • 44
Utku
  • 724
  • 1
  • 7
  • 12
  • 6
    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
  • 10
    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
  • 1
    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

2 Answers2

33

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

Hector
  • 10,893
  • 3
  • 41
  • 44
  • 3
    `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
  • @Arminius - Because the connection being encrypted means you can't read data in transit but its not the same as the sender checking they are talking to a legitimate party. I regarded OPs main question as "are magic sign in links sent via email bad practice". I'll update to cover links alone. – Hector Jan 15 '18 at 16:14
  • 9
    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
  • 3
    @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
  • @Arminius *End-to-end* encryption, on the other hand, is where the message is encrypted by the sender themselves and is only decrypted again by the recipient. At any point that the message travels to or from (or between) mail servers, it is encrypted, regardless of whether the actual connection between servers is encrypted or not. This means that if an attacker were to intercept an unencrypted connection carrying such an email, all they would see is the encrypted email. This kind of encryption is (unfortunately) rarely used with email because it's (still) too complicated for most users. – Micheal Johnson Jan 15 '18 at 22:02
  • @corsiKa - i'm not saying they can't have two logins - but to do so you have to store them in a separate table. At this point you see a lot of implementation bugs. And of course you shouldn't aim to be vulnerable to SQL injection - but developers get lazy and code reviews miss things. If your db is breached you're in a much better recovery system if the attacker doesn't have every users current credentials. Meanwhile i wasn't talking about more flexible to overwrite - by "suggested method" i meant the signature based approach in the original answer. – Hector Jan 15 '18 at 22:11
  • @MichealJohnson - EndToEnd also has pitfalls unless additional protocol steps are used. Message replay based DOS for example - in this case an attacker could drop legitimate messages replacing them with prior codes. The messages for all purposes look legitimate and were encrypted with the original senders key but the receiver cannot log into the service with them. – Hector Jan 15 '18 at 22:16
  • @MichealJohnson Well, the answer refers to MITMing *the* (singular) encrypted connection. Personally I found that entire paragraph a little vague which is why I was asking for some elaboration. – Arminius Jan 15 '18 at 22:18
  • @Arminius - I wrote "traffic may be encrypted between servers" (plural). I didn't go into more detail because the root question wasn't specifically "why is encrypted SMTP not secure" / this information is very easy to find. – Hector Jan 15 '18 at 22:21
  • @Arminius The reason that encrypted content can be MITM-ed relates to the observation that encryption is not the same as authentication. Email relays decide which server to forward a message onto by requesting a DNS MX record for the domain. DNS is not encrypted or authenticated, and is vulnerable to spoofing by a well-placed attacker. So an attacker could trick a relay into relaying the connection via their server (in a domain they control, so they can get an SSL cert if they want). At that point, it doesn't matter if the connection is encrypted, since the attacker is now a man-in-the-middle. – James_pic Jan 16 '18 at 12:22
  • "*If you implement this system using the user table you risk impatient users requesting a second code and them arriving out of order*" only if your implementation doesn't do rate-limiting. If you're using a DB to record token generation it's not hard to limit it to once per 24 hours. – Peter Taylor Jan 16 '18 at 14:40
  • @PeterTaylor - then users that are behind email anti-spam products that greylist until a retry are stuck waiting for 30+ minutes until they can log in. – Hector Jan 16 '18 at 14:50
  • Huh? I don't think I understand your scenario. If the greylisting software raises higher barriers to properly implemented MTAs making retries of a single message than to senders who spam multiple messages then it seems more like a pro-spam product. – Peter Taylor Jan 16 '18 at 14:56
  • @PeterTaylor Most spam is fire/forget. Greylisting rejects the first attempt from unknown sources (usually IP, sender address, receiver address triplet) with a server busy response. After a set interval the remote server should retry - Usually has to be at least a few minutes to be accepted. Often this is more like 30 minutes (email was never designed to be realtime). So if an impatient user clicks resend after a couple of minutes often the second email will come through (followed by the first when the server gets around to a retry). For properly implemented MTAs everything works as designed. – Hector Jan 16 '18 at 17:47
  • 1
    You can also constrain a magic-link to the device that initiated sending this link, using a session cookie of some sort. The magic link would only work on that same device, to authenticate that session. That minimizes the risk of a magic-link getting stolen. – Tim Visee Jun 28 '19 at 15:53
  • 1
    @TimVisee: A clever idea, though the benefit is minimal. This changes the attacker approach from: "Construct a magic link theft tool, then visit magic link when generated" to: "Construct a magic link theft tool, visit the website and ask for a magic link, then visit the magic link." Note that the latter can also be used to "steal" expired magic links (by generating a new one). This also runs the risk of user failure, since some users will unknowingly end up with a new browser session when clicking such a link. – Brian Jul 01 '19 at 13:31
24

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.

Philipp
  • 48,867
  • 8
  • 127
  • 157
  • 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,.. – Jonas Czech Jan 15 '18 at 17:36
  • As I see it, all the 3 problems are essentially the same with reset password link and sign-in link. – Tero Lahtinen Jan 15 '18 at 18: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