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.
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
Just seed it with something the attacker could not know:
There is no limit at how crasy you could go
Way too much but you get the idea.
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.
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).