3

I'm intending on using a hash to generate a verification token for verifying email addresses. The hash would be generated like so:

email:username:salt

The hash is generated with the SHA256 algorithm and the same salt is used for each token generated.

The alternative, and more commonly used, method is to generate a one time UID which is stored in the database and acts as the verification for the new email address.

My question is: is this an efficient (taking processor and disk utilisation etc.. into account) way of achieving the generation of a token for email validation.

Steffen Ullrich
  • 114,247
  • 10
  • 131
  • 172
Matt Brown
  • 355
  • 1
  • 4
  • 12
  • 1
    I think each user account should have its own random hash. Efficiency is not really a concern in the context of account creation, because this is a fairly rare event, not happening every often. – Tim Biegeleisen Aug 18 '16 at 16:07

2 Answers2

1

The whole purpose of email verification tokens is to generate a token from your secure web server, and email that token out to someone so that they can click a link which contains that token, so you can then verify their account.

The important things to keep in mind:

  • The token must be impossible for the end-user to reproduce, otherwise it can be faked.
  • The token needs to be cryptographically signed by your web server (ideally), so that the CLIENT knows this is a valid token. This also is important because when the user sends this token BACK to your server, you can verify that YOUR server is the one that created it.
  • The token needs to be expireable: you should be able to 'expire' this token if it is not used within a certain amount of time: 24 hours, 3 days, etc.

For this reason, I would not recommend the approach you're taking.

Instead, I would use a JSON web token (this is an ideal use case for them). This other SO question has a decent summary.

Using a JWT will let you:

  • Create the token on your web server.
  • Set an 'expirey' date on this token so it can't be used after a certain time limit you specify.
  • Encode any user-specific data in the token you want: usually a user ID or something similar.

When the user sends the token back to your web server, a JWT will:

  • Guarantee that the token was generated by your server and not someone else maliciously.
  • Guarantee the token is still valid (in terms of timestamp).
  • Guarantee the token hasn't been tampered with.
  • Let you view the previously encoded token data (user ID / etc).

I hope this helps =)

rdegges
  • 32,786
  • 20
  • 85
  • 109
  • Is the JWT approach pretty much the same as the hashing approach that I suggested in the original question but with an additional timestamp, or am I missing something? – Matt Brown Aug 18 '16 at 18:09
  • It uses a server-side secret to cryptographically sign the token. It has more security than what you're doing because it uses a combination of factors for entropy, and not just the factors you've listed (which can theoretically be guessed). – rdegges Aug 18 '16 at 20:31
  • Sure, I'm just thinking that the salt (which is referenced to as the secret key in the wikipedia article) is as likely to be guessed in the scenario I've mentioned as the scenario you've mentioned. Would you mind explaining what additional factors are used using JWT compared to just hashing the ID, Timestamp and email address (and using this as a signature). – Matt Brown Aug 18 '16 at 21:39
1

What you're doing is somewhat secure.

I would refer to your salt though as a key - you are generating a keyed hash. Ensure that you generate a key with sufficient entropy. I would recommend a strength of 128 bits generated by a CSPRNG.

Some keyed hashes generated in this manner are vulnerable to a length extension attack. That is, if an attacker has generated a validation token for foo@example.com then they will be able to work out the hash for foo@example.com.example.org. This is because the output of a hash algorithm also betrays its state. To mitigate this, you could use the HMAC algorithm.

Your current approach also has the limitation that an email address always has the same token. If an email address expires (say Bob Smith with email bobs@example.org is fired from his job at Example Organisation, he will know the verification code that the next Bob S. will get when he starts working for Example Organisation). Whether this is any risk to your application is for you to decide. To mitigate this, you could use JWTs instead, which will enable you to put an expiry date into the token that can be validated. JWT's HS256 algorithm also uses an HMAC, solving that problem too.

Using keyed hashes should be efficient, and doesn't have the storage, maintenance and overheads of database lookups.

By UID do you mean UUID?

Remember that:

the purpose of a [UUID] is to be globally unique, not to be unguessable.

and

[UUIDs] are designed for uniqueness, not for security.

You would be better off generating an 128 bit token on the fly using a secure source of entropy (say another CSPRNG). You may want to hash these (without salt) on the server-side using SHA-256 to prevent any data leakage vulnerability from meaning an attacker can validate any email address.

SilverlightFox
  • 32,436
  • 11
  • 76
  • 145