2

For the registration on my PHP powered website, I require email confirmation. After a user registers, a string is generated with the following code and sent to their email address.

$key = md5(mt_rand(1000,999999).$_POST['email']);

That string is also stored in the database, and if the user pastes the correct key in to my confirm page, their account is validated.

Is the key generation code I used secure? As in, is there any way one could ascertain the original email string if they obtained the key?

1
  • Why does the key need to be derived from the email at all? Generate a random key (following @Adnan's advice) and associate it with the relevant user's record in the database. Commented Mar 16, 2014 at 9:42

3 Answers 3

5

Short answers: No, your key generation isn't secure. Yes, the attacker can find the email from the code.

An attacker can obtain the activation code for any email address due to the extremely weak random number generation. mt_rand() isn't suitable for this purpose, add to that the advantage gained by knowing some information about the state of your system (time of generation, for example). That can severely lower the space for the potential keys for each email.

As for the other point, I don't think it's such a big concern that the email can be brute-forced from the key. That's should be the least of your concerns. The key is, presumably, short-lived and only sent to the email address. Having the owner of the email address finding out their email address is.. well, you get the point.

However, yes, it's not very difficult to brute-force the email from the key. Mainly because emails are most certainly not randomly generated and will very likely exist in dictionaries with some other combinations. Your random number gives you about 1 million combinations, that's very low.

"How can I do it better?", you ask. It's very simple. Use a secure random number generating method/API offered by your language of choice. In your case, in PHP, you can utilize openssl_random_pseudo_bytes(). Here's an example for your convenience:

$activationKey = bin2hex(openssl_random_pseudo_bytes(16)); //128-bit

After generating the key and sending it to the user, store a hash of the key in the database. Almost any hash function will do, I recommend SHA-1. When the activation link/key is used, you simply hash it and compare it to the entry in the database. After that, you can activate the account and invalidate the key.

6
  • 1
    Even better: generate the key and email it to the user as you describe. Then hash the key and store that in the database, discarding the original key. When a user attempts to confirm their email address, hash the key provided and compare against the database. Commented Mar 16, 2014 at 9:05
  • I will implement Adnan's method for key generation. The hashing of the activation key in the DB would prevent users from mass activating accounts in the case of a database breach? I assume doing both of these things would not noticeably effect performance. Commented Mar 16, 2014 at 15:04
  • @StephenTouset Thanks for the addition. I've added it to the answer.
    – Adi
    Commented Mar 16, 2014 at 15:08
  • @PhilippeGray Operations of this sort usually have a negligible effect on the performance. If you found this answer, or any other answer, satisfactory, useful, and solves your problem, then you may use the little check mark (tick) near the top left part of the answer's area. This helps future visitors to know which answer solved the problem in the question. Good luck.
    – Adi
    Commented Mar 16, 2014 at 15:10
  • @Philippe Gray If your database is breached, you would have more issues than having the attacker mass activating your user's accounts. And, hashing the activation key won't prevent the mass activation of accounts in the case of database breach as the activation key is the "secret key" that you should keep a hold of securely. It doesn't matter of whether it is hashed or not.
    – wcypierre
    Commented Mar 16, 2014 at 16:20
0

Generating the hash would not be much of an issue as rand() is not random enough.

For the random key generator, if you're on linux/unix, you could get the values from /dev/urandom instead of rand() which would be good enough for your usecase.

And yes, by submitting a valid hash that gets an account validated, you would be able to deduce one's email address(at that time, your application would probably show the email address or the username of the user at the validation page which would somewhat do the same thing).

However, despite that the emails can be retrieved via this way, I would say that it is not really much of an issue as you can deduce it as well via the login page or forgot password page if your application does not cater for such conditions. Another point would be that, after the user is validated, the validation link should be dropped from your database so the attacker cannot will not be able to deduce the email for that email account anymore. Hence, the email accounts that could be deduced would be the ones that are not active(as the account is not validated yet) or new accounts. And still, it doesn't have much impact as gaining one's email address alone will not do you much.

A bit offtopic, but I feel the need to say this since it is somewhat related.

That aside, getting the attackers to validate your user's account or getting the user's email address is not really much of an issue, however, if you allow the user to login directly after validating their account, then the attacker would be able to gain access to the user's account which is bad(which is somewhat common as well, unfortunately).

Hence, the proper way would be to only validate the user's account upon activation and not letting the user to login directly into their account.

3
  • Regarding your third paragraph. The concern here isn't an attacker validating a legitimate user's account. The concern here is an attacker mass validating accounts with fake email addresses in order to successfully spam the targeted site.
    – Adi
    Commented Mar 15, 2014 at 21:44
  • Hi, while I do agree on that, and I have already stated that it will be a bit offtopic, but if that code goes into production and it is as what I've said, then the users of his site will get hacked which is bad anyway.
    – wcypierre
    Commented Mar 16, 2014 at 2:20
  • @Adnan, I've added some more explanations in accordance to the main topic.
    – wcypierre
    Commented Mar 16, 2014 at 2:41
0

As in, is there any way one could ascertain the original email string if they obtained the key?

Given an attacker who has already obtained the MD5 hash value (i.e. they have obtained the key), an offline attack is now possible.

Since oclHashcat using 8x AMD R9 290Xstock core clock can generate MD5 tries at over 80 billion (with a B) tests per second, and your random number is slightly under a million, oclHashcat with those GPU's can test 80,000 different email addresses per second.

Since email addresses are very predictable, are not uncommonly used as passwords, are normally considered public information, and are available in bulk from previous data breaches as well as mailing list records and for sale and so on and so forth, they're very vulnerable to rules based dictionary attacks, as well as combination attacks (a-z+last names + @hotmail.com or @yahoo.com or @gmail.com, for example).

Further, numbers on the front and end are a common password trick people like, so rules-based dictionary attacks and mask attacks checking for that kind of thing are already in common use.

Thus, yes, the email address could be found out from just the hash you sent if it's common enough.

4
  • I don't see how that relates to the question. The user already knows their email. They just don't know the random value. Offline search like hashcat doesn't apply either, you need to run an online search for the random value. Commented Mar 16, 2014 at 12:51
  • @CodesInChaos - from the last sentence in the original question: "As in, is there any way one could ascertain the original email string if they obtained the key?" - I answered from this perspective - an attacker who has already obtained one key (i.e. one "$key = md5(mt_rand(1000,999999).$_POST['email']);") and is now attempting to find out the email address from that. I've updated my answer to make that more clear (two sentences added at the beginning). Commented Mar 16, 2014 at 17:12
  • But what's the point in trying to do that? We're talking about email activation here, where you want to obtain a valid code for an email you don't own. Commented Mar 16, 2014 at 17:19
  • @CodesInChaos - That's the question that was asked - could an attacker figure out the original email string from just the key? You'd have to ask Philippe Gray if you wanted to know the point. Presumably it has to do with privacy concerns, though I did mention that email is normally considered public information in my answer in the paragraph "Since email addresses...normally considered public information...", as that also helps the attack the question asked about. Commented Mar 16, 2014 at 17:25

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .