How to generate a secure activation string in php?
Asked Answered
A

6

19

After user subscribe email to my website. My website will generate an email confirmation and send to them. In the email content, i need to include activation key, something like:

www.domain.com/activate.php?key=$generatedKey

How do you generate the key? using sha1($email)??

After generate the key, i store it in database, so that when user click the link I can verified it with the database?? I am new to it, please advise.. I need an Email Confirmation script..

Assail answered 18/5, 2009 at 3:29 Comment(0)
D
26

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).

Defrost answered 18/5, 2009 at 3:34 Comment(6)
No chance of collision is you add the user ID to the URL as well and check that they both match.Unsuccessful
@Eli, there is a chance, as some collections of characters do hash to the same hash string. Though the chance is quite negligible (but still there).Yenta
Ehh, I'm not a fan of revealing primary key information to the user. But that is a good idea, Eli. so key=$generatedKey&id=$uidDefrost
Cool.. after user account activated, should I removed the activate key? If user want unsubscibe, how?Assail
Yes, I would set it up so the activate key only works once. If you need another, generate a fresh one. And alex, I don't think that's relevant here -- we're just using the hash as a random character generatorUnsuccessful
Wouldn't including the user's email in the string make the key less random/secure? Also, I would suggest storing the time when the code was generated so it can be made to expire after a certain amount of time has passed.Pylorus
W
7

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.

Walther answered 18/5, 2009 at 4:34 Comment(1)
Very good summary of options and their pros and cons! I'd only add that no matter which option you choose, there are some "invariants" which are true for all of them. For example: 1. The activation link have to be unique, as a whole, because if it's not, you can't tell which user to activate. 2. You have to store at least the e-mail address in your DB, and it must be unique too. In this view, the con of the first option is not so much a con, because you'll end up checking the uniqueness anyway (of the e-mail address at the very least).Cleodell
K
1
$guid=md5(uniqid(mt_rand(), true));
Keek answered 18/5, 2009 at 3:34 Comment(0)
U
1

If you're storing the activation string in the database and checking it later, you don't need a hash at all!

You just need a long, random string. You can generate it however you want, just make it long. In fact, it should ideally have nothing at all do do with the email or username.

Unsuccessful answered 18/5, 2009 at 3:54 Comment(2)
That's why sha1, md5, and other crypt functions are good as they create seemingly random strings. If you want strings that are unique (low collision), your best bet is to base them off of some unique constant (email) and some additional salting.Defrost
Hash functions don't add any entropy so they don't make collisions any more or less likely in this case. They just look more random to us humans.Unsuccessful
C
0

That should do it, however you can improve it by adding some salt, example:

$key = sha1($email . 'doYouLikeSauce');

Other approach is just to generate a random password and send it via email.

Concinnate answered 18/5, 2009 at 3:34 Comment(0)
T
0
$code = md5($_POST['username'] . microtime()); 
Tatiana answered 10/6, 2015 at 5:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.