3

I need to send verification emails for things like

  • email verification
  • password reset
  • email change
  • password change

In the past most webapps would send an email with a clickable verification link that I'd click to go back to the site and complete the process.

These days I see many webapps instead send an email with a verification code that I must copy-paste into the browser, and sometimes it's a short random number that is easy to type manually (e.g. because I'm working on my desktop but I read the email on my phone).

What are the pros/cons to these two approaches?

I feel the "new" way is more UX than security, but I'm unsure. Which is more secure, and what tradeoffs should I consider?

  • 1
    I suspect that the reason for this trend may in fact have much more to do with optimising deliverability than it having any benefits from a security perspective. Spam filters for example are far more likely to register false positives for messages with <a> tags especially when the value of the psudorandom confirmation parameter looks very much like an affiliate or tracking value which it very much will. Sure this isn't an issue with many filters that simply drop the message in a spam folder but even that can be bad for user experience and some filters may event prevent delivery at all. – MttJocy Jul 22 at 19:28
4

The overall goal is to verify that a user can be reached through the email address.

This is done by creating a token, and any way of delivering that token back to your server will do, whether it is having the user click a link or copy/paste (or retype) a code.

Since your list includes password resets and email resets as reasons why you might send a token, keep in mind that these have additional concerns beyond simply verifying that an email will reach the user. Attackers may try to guess the tokens.

Longer tokens may be more difficult for an attacker to guess, but users may be less willing to type them.

On the other hand, usability always plays a role in security. The best security isn't the strictest; it's the security that people will use, and especially that they won't seek workarounds for.

People who are security conscious are increasingly less willing to follow links in emails. People who are habituated to following links in emails are also more likely to follow phishing links in malicious emails.

In addition, users may not have access to their mailbox with the computer that they're using, or may not be using the same web browser that their email client opens by default. I.e., the default email clients on mobile devices may open the default browser that comes with the phone/table, rather than a browser that the user installed later and uses regularly.

Thus, for a simple email verification, or for a second factor during login, short codes that a user types are good enough, so long as they're generated using a cryptographically secure pseudorandom number generator (CSPRNG) seeded by a high entropy source, such as /dev/urandom or a similar system on your platform. You can also include a link that will have that code, in case this is easier to use by the user, rather than copying and pasting the code. The key here is that, for something that is common (i.e., daily), make it as easy as possible for the user to increase their security.

If the user is trying to change something about their account's security, though, such as changing their password, changing their contact information (email address), or changing any part of their 2nd factors (also in your case, email address), you should make the token longer, to the point where it doesn't make sense to have users type it in. Still use your high entropy source to seed your CSPRNG, of course.

In all cases, these tokens should have a very limited life, up to a few hours. Make them single-use only (so that a user can tell that someone used their token first or, if the eavesdropper is slow, the eavesdropper can't reuse that token), and make the token usable only by that one account. (There are stories of people generating password reset tokens for themselves, then changing the user ID to someone else's, gaining access to their account that way.) All login and password reset attempts should be throttled both by IP and by account, and failed attempts should be logged.

  • Your point regarding increasing user suspicion of links here is a good one, my initial thoughts on the potential reason for this change were on similar lines of growing suspicion though from the deliverability perspective. Namely of course that email filtering software is much more suspicious of messages with links in the payload especially links with parameters that resemble values designed to identify a user or confirm a spam target address is live and being accessed ie most anything resembling a one time use psudorandom string for example. – MttJocy Jul 22 at 19:36
  • That's a good, subtle point, @MttJocy. I'd suggest that, since the initial account verification email is there to make sure the user can get your emails (and by extension, that your emails can pass through spam filters), that this verification email should look as spammy as the spamiest email that you send, according to their filter. The user is motivated enough to create an account, so they should be motivated enough to check their spam folder and mark your service as not spam, which is something that isn't guaranteed if they forget their password after not using their account for a while. – Ghedipunk Jul 22 at 20:14
  • Thanks! You seem to advocate for verification codes in general, but for verification links specifically for highly-sensitive mails like email confirmation, password reset, email change, etc. However, why not just use codes for them too? Those codes are used only once, and even though they're short cannot be easily guessed (and would set off your IP throttling if some attacker tries to guess them anyway). – lonix Jul 23 at 10:47
  • @Ghedipunk Perhaps though it's also worth noting that most modern spam filters include at least some degree of learning behaviour whether this being as simple as learning what senders have been seen before and that generally sent non suspect messages. Or whether this be because they use a user feedback mechanism like a "This is spam" button that they use to learn to trust senders more if they send messages that do not get flagged. Either of these of course will tend to be somewhat more likely to flag a message from an unknown sender though how much will depend how zealously they are configured – MttJocy Jul 23 at 15:31
  • @lonix, I'm more advocating to use short tokens with both visible codes and clickable links for low security and extremely short lived tokens, to improve usability, and long tokens for high value targets that might be automated and brute forced, such as the forgot password/change password functionality. People can type in a new 6 character code daily... I suppose, if a user wants to type in a 24 character code for a password reset, you can make the token available in a readable form, but don't expect them to ever use it when a link is available. – Ghedipunk Jul 23 at 15:43
1

For me it was a matter of how efficient the verification process was and how well it actually worked in practice.

[ verification code ]

  • can be generated with the specific complexity you need/want

  • will most likely reach target

  • can be protected itself in various ways from interception (like being sent as a small picture or even as a blurred captcha-like picture)

  • nothing prevents you from typing a code to an already opened web-page

[ verification link ]

  • may fail to actually reach the target (maybe be blocked by excessive spam filters)

  • may be intercepted and analyzed which then could lead to a breach in your security

  • it may never be clicked by users as any company that has basic security will train it's users to be extremely careful with opening links, policy usually being not to click them by default

  • even if users want to click them, links may or may not work depending on company policy and security (outlook can block them, anti-viruses can block them, other security measures can block them)

For the reasons above, I'd go with verification code at any time.

As a note, large online gaming companies (like Steam, EA, Crpytic and many others) use the same method: they send a code or a code within picture.

  • I like your idea of using a code for all scenarios as it's easier to implement, but, as @Ghedipunk mentioned in his answer, for things like password/email change/reset, it may be better to use a link with a longer token. What do you think of those scenarios, would you use a link or code? – lonix Jul 23 at 10:27
  • 1
    Implementation difficulty aside, generated code it has a higher chance of success, of reaching users compared to links. As you make a longer token you can simply also generate a more complex access key/password, so I still would not favor the usage of links. – Overmind Jul 23 at 11:25

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.