How to generate a secure activation string in php?

You basically have a few options:

1) Create a single unique identifier that is seemingly random and store it in your database with which username it corresponds to

2) Generate a random password and include the user id and password in the link and store the password in the database

3) Use a one way hashing function (md5, sah1, etc) and a secret identifier to encrypt the user identifier. You don't have to store the encrypted user identifier in your database.

Option 1 is difficult because you have to worry about checking the database to see if the key already exists. However, it is nice that the URL does not contain the username being activated.

If you are already going to use some sort of database to store the user information (probably a password at minimum) in the future, you could go with option 2. It doesn't take a lot to add another column to your database. When sending the email, save the username and something like $key = sha1(rand(1, 99999) . $username) in another column for the row that contains the username. Then have your link look like this: http://you.com/activation.php?user=$username&key=$key. In activation.php you check to see if the key is equal to the value stored in the database.

If you want to use less storage space in your database, option 3 will work. You can use something like $key = sha1($mysecret . $username) as the secret identifier. Use something odd that only you know as $mysecret such as 'aaafj_my_secret_adfaf'. Use the same type of URL as in option 2. However, because you can generate $key based only on $username, you don't need to store it. So when you are processing in activation.php, just check to see if sha1($mysecret . $_GET[username]) == $_GET[key]. If it does, you know you have the correct user. Theoretically, with enough registrations, someone could figure out your value for $mysecret and generate the activation keys too. However, you would surely notice the billions or more of registrations that it would take before they could begin to calculate what it is. The number of activations required is based on the key size of the hashing function. Use sha1 (160 bit) vs md5 (128 bit) to make it harder to guess your $mysecret value.


Personally, just I use a combination of things like:

$generatedKey = sha1(mt_rand(10000,99999).time().$email);

The chance of collision is small, but I recommend checking your database first before sending it out (using UNIQUE constraints is an easy way).