4

In Can anyone provide references for implementing web application self password reset mechanisms properly? it is mentioned to use strong cryptographic randomness to generate the reset token that is emailed.

If we used microtime() an attacker could only guess to within 1 second so they would have to brute force thousands of possible tokens.. but the token can expire after a single failed attempt.

With mt_rand() an attacker would need to reset 700 passwords to get enough information to piece together the random state, but that's assuming each call is consecutive.. other people making use of the site would make trigger mt_rand calls that the attacker is not aware of.

So it seems in both situations the attacker is thwarted. Of course it's better to be safe than sorry so it's better to use cryptographic random numbers but I'm wondering if it's an actual vulnerability not to.

  • Please search the forum, you can use random time plus the random 128 byte random initialization vector, and then you encrypt it with AES and this way it's OK. For AES you need a key which you can store on the server. – Andrew Smith Aug 02 '12 at 17:18
  • @AndrewSmith, I do search the forum –  Aug 02 '12 at 17:22
  • Search for the posts about encryption and random iv - only encrypted data is safe, the rest is easy to crack with tools and methods. – Andrew Smith Aug 02 '12 at 17:38
  • 2
    @AndrewSmith I'm sure the OP knows that these function are not a good choice. But it's certainly interesting to find out how bad they really are. – CodesInChaos Aug 02 '12 at 21:36

4 Answers4

7

This paper shows several attack methods on PHP's random functions. At the end of the paper you can find an example of a secure token generation function.

Zzz
  • 756
  • 5
  • 9
  • Such sharp results in this paper, exactly what I wanted to know . Thanks a lot! –  Aug 03 '12 at 04:23
  • I am not sure about this secure token generation, particularly 64bit urandom based key. 256bit is used for purpose, and for average website you should use 128 bit keys today at absolute minimum assuming strong PRNG. – Andrew Smith Aug 03 '12 at 11:04
2

No, mt_rand() and microtime() are absolutely not safe at all. These are both 32bit numbers. A decent key is fully random (not time) and at least 128bit in size. Also mt_rand() is not cryptographically safe so it doesnt produce really random numbers which would be usable for this task.

You need to get 128bit key from /dev/urandom, which is better, it is 16 or 32 characters, and then you can hash it with salt, or encrypt with AES using another 128bit symmetric key, which you can obtain from /dev/random, which is slower, but the entropy is higher.

Andrew Smith
  • 1
  • 1
  • 6
  • 19
1

This is one of the border cases where although one cannot definitively answer it with a clear, decided "No! This is how I could break it.", one still has to say "... but why do you want to do this if it is that easy to do it right?".

Can an attacker exploit microtime being used as token? At least in theory, the answer must be: "Definitively, and easily". I haven't tried, so I couldn't tell for sure how hard it is, but it is certain that it is possible.

Can an attacker exploit microtime fed into mt_rand? Possibly, unlikely, almost certainly not. At least not with a compellingly high chance of success, and not without considerable work. Does that mean it's secure? No.

On the other hand, it doesn't really cost you anything to
a) use a token with more bits (32 really isn't a lot)
b) use a token that is unpredictable (strong random generator)

I would use a 64 bit token (128 if you are paranoid). Using a 128 bit token is of course much more secure against brute forcing, but since tokens have a limited lifetime of a few minutes and the amount of requests that can be sent over the network is limited, 64 bits should be just fine (and in case the user needs to type the key in, it means only half as much hassle for the user, also only using 64 bits will deplete the generator from entropy more slowly).

If your server has a gigabit uplink, it cannot possibly receive more than 1.1 million frames per second (assuming UDP and 8 bytes payload). If your tokens are valid for a "normal" amount of time, like e.g. 15 minutes, the chance of success of getting a hit while saturating the link during that time is 10-11. Also, apart from the diminuitive chance of success, if someone completely saturates the link for several minutes, this will not likely go undetected.
Setting up a huge botnet will be of no avail either. They can of course DoS you, but no matter what, no more frames can make it through the cable (physical limitation).

Compare that to a scenario where I might be guessing some correct token from another token that you have sent me or that I have eavesdropped with a chance of, say 1 in 100 (this should be feasible for a timer with the resolution of microtime) simply by looking at the clock! Or compare it to a scenario where I can derive the state of your generator from 623 consecutive messages.

Even if I am rather unlikely to succeed at once, there's galaxies between this and a secure approach (and they both cost you the same).

Damon
  • 5,001
  • 1
  • 19
  • 26
1

You describe using microtime() and say one incorrect attempt invalidates the token. First, an attacker tries out doing one reset from an account you control to see how the token is generated. Maybe they find out it looks like an encoding of a unixtime set to some particular time zone. The attacker tries estimating the delay of the system (network time; CPU time). Yes, any particular attempt is likely to fail. But if your attacker with their botnet tries ~10 attempts a minute it would take about a day (if they can estimate the time to ~0.1s before you'd break in) or a week (~1 s accuracy).

Sure you could possibly lock the password reset mechanism account after too many incorrect attempts (but how would it be unlocked?), could this frustrate legitimate users? Oh you put a captcha on the page? Well know the attacker has to use amazon mechanical turk to defeat the captcha at a cost of ~$2 per thousand captchas (so it costs ~$20 to break into an account with a captcha). But again, if you can find existing a list login names easily (say at the account creation page if it informs you that a username is already in use), they don't have to attack any specific account. E.g., they change the account they attack nearly every time; possibly (with botnet) change the IP nearly everytime, etc.

In summary, its pretty trivial to implement this in a bulletproof secure manner, so why would you ever want to do it insecurely, where you expect any attacker off the street has a 1 in 100000 of getting in on any particular attempt? Versus getting some random 128-bit string where they'd have a 1 in 340 000 000 000 000 000 000 000 000 000 000 000 000 chance of randomly guessing it.

dr jimbob
  • 38,768
  • 8
  • 92
  • 161