10

I am using the following code in my code to send a password reset token to a user.

$token = md5($user_id . time());

Why this is considered as a bad approach being cited as it has a weak entropy. The above code would generated a scary looking 128-bit token that you an attacker cannot decipher at all.

My question is why this is a wrong approach? How do I say it has a weak entropy? Is there a way I can calculate its entropy?

1
  • 11
    MD5 cannot be reverted. But this is entirely irrelevant here, because an attacker only has to guess the user ID and the time when the token has been created. Then it's trivial to calculate the MD5 hash.
    – Ja1024
    Commented Sep 16 at 9:52

3 Answers 3

34

$token = md5($user_id . time());

The password reset token is supposed to be secret. However, it is derived from values that are not secret, or at least not hard to guess.

The attack scenario is as follows:

  • an attacker requests a password reset for user with id 123.
  • they calculate the password reset token, by doing $token = md5($user_id . time()) themselves.
  • they navigate to the password reset page and reset the password of user 123.

The problem is with step 2, where the attacker can calculate the password reset token themselves. If the reset token was random, or contained some secret information, this would not be possible.

Perhaps user IDs are random and not public, but can be presumed to be between 0 and 232. In that case, the attacker has to perform at most 232 password reset tokens before they can reset the password. In this case, the entropy can be said to be 32 bits.

In cases like this it is not really useful to think about entropy at all. Just think about whether an attacker can calculate the reset token themselves with the information they have.

29

Just a few additions to Sjoerd's answer:

It doesn't matter that the result is 128 bits long (you wrote 32 bits, but you probably meant hexadecimal characters). It's also irrelevant that MD5 cannot be reverted. In fact, MD5 may be completely useless here. The only inputs to your token are the user ID and the Unix time. Both are extremely weak:

  • User IDs are typically public or easy to find out.
  • The time when the token is created can be influenced by the attacker and is then easy to guess.

To fix this problem, get rid of this approach altogether and use a proper cryptographically secure random number generator. Those are specifically designed to resist any prediction attempts. In PHP, use the random_bytes function with a sufficiently large output (e.g., 16 bytes), and then encode the result a hexadecimal number (or whatever format you prefer).

$token = bin2hex(random_bytes(16));
13

In addition to the other good answers. From your question I also take away that you don't see why it's insecure since the attacker just gets "a scary looking 128-bit token that you an attacker cannot decipher at all".

This is also called security through obscurity.

In cryptography you want systems to be secure even though the attacker knows how the internals work. This is called Kerckhoffs's Principle.

Once the attacker knows how you calculate this id, they could relatively easily generate it themselves, given they find out the user id.

1
  • 13
    Also: "scary looking" is relative. Someone who knows what he's doing finds a MD5 hash familiar, not scary.
    – Martijn
    Commented 2 days ago

You must log in to answer this question.

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