8

When users register an account they get an email with a verification code that they can click to verify their accounts.

This is how I generate the verification code.

md5(rand(0,1000)

Is using the method below a bad choice? It generates a random number between 0-1000. Since there are only 1000 options, and their MD5 hashes are known, it should take an attacker just a 1000 trials to verify the account without it really belonging to them

dave
  • 1,043
  • 1
  • 10
  • 18
  • "it should take an attacker just a 1000 trials to verify the account without it really belonging to them" That's why you need rate limiting as well. – NullUserException Sep 09 '10 at 02:26
  • @NullUserException what rate do you limit? Attackers will use multiple IP addresses and will attempt to register multiple accounts... – Bruno Rohée Jun 10 '14 at 12:01

3 Answers3

5

This thread How to generate a verification code/number? has some good thoughts on the matter. Hashes, reversible hashes, check-digits... plenty of options depending on your needs.

Community
  • 1
  • 1
Farray
  • 8,290
  • 3
  • 33
  • 37
3

rand(1,1000) is 10 bits of entropy. MD5ing it adds none. On average it will take 500 tries for an attacker to verify an account. No amount of rate limiting will help you, as skilled attackers will rent or already own a botnet that will be used to validate the accounts.

Play it safe and have 128 bits of entropy in your verification links. In PHP openssl_random_pseudo_bytes(16, true) is the portable way to get cryptographically strong random bytes, but if you host under some Linux distribution or one of the BSD OS, reading /dev/urandom is also an acceptable choice.

Also question the wisdom of verifying accounts at all, many people use untraceable disposable emails exactly for that (and no your blacklist won't ever be up to date).

Bruno Rohée
  • 3,436
  • 27
  • 32
2

Just seed it with something the attacker could not know:

md5(rand(0,1000).'helloworld234');

There is no limit at how crasy you could go

md5(md5(time().'helloguys'.rand(0,9999)));

Way too much but you get the idea.

Iznogood
  • 12,447
  • 3
  • 26
  • 44
  • 4
    the more entropy, the better. I'd put at least the user ID or email of the person registering, along with the time to the greatest precision possible. –  Sep 09 '10 at 02:27
  • 3
    @John Well i taught of suggesting some seed generated from the spin of an atom but you know the cost and all that. – Iznogood Sep 09 '10 at 02:30
  • rand() is horrible and should never be used for security, mt_rand() is better. Also the attacker knows time(), he is the one creating the account. – rook Sep 09 '10 at 04:30
  • @Rook: mt_rand is also seeded by time. It is still difficult for the attacker to guess the time right down to the millisecond (and guess the salt "helloguys"). – Olhovsky Jan 05 '12 at 06:18
  • @Olhovsky yeah, but /dev/random is better. – rook Jan 05 '12 at 06:55
  • @Iznogood it's all based on the secret staying secret, the odds ain't that good with it being live on the server. Why not play it safe a,d read 128 bits from /dev/random... Your solution is playing with fire, someone gonna get burnt. Dangerous advice. – Bruno Rohée Jun 10 '14 at 11:47
  • MD5 should never been used to anything security related. – ztripez Jun 10 '14 at 12:01