Bug #1977

mod_usertrack generates same cookie value on different lighttpd instances

Added by olemartin almost 5 years ago. Updated almost 5 years ago.

Status:FixedStart date:2009-05-07
Priority:LowDue date:
Assignee:-% Done:

100%

Category:-
Target version:1.5.0
Missing in 1.5.x:

Description

We are using mod_usertrack in a "clustered" environment with several servers. If two new users are requesting a page from two different servers during the same second, they get the same cookie value.

Could you please add something that makes the value more unique?

http_auth_mod_usertracks_entropy.patch Magnifier (2.93 KB) origo, 2009-06-10 23:45

Associated revisions

Revision 2524
Added by stbuehler almost 5 years ago

Add support for "real" entropy from /dev/[u]random (fixes #1977)

Revision 2525
Added by stbuehler almost 5 years ago

Add support for "real" entropy from /dev/[u]random (fixes #1977)

History

#1 Updated by stbuehler almost 5 years ago

  • Priority changed from High to Low

The hash includes rand(), and that should be enough imho. (I guess the call to srand() is missing.. but i don't think srand(time(0)); would help in critical cases, as you probably started them at the same time).

And you could of course your own usertracking with mod_magnet and the magnet.attract-raw-url-to handler.

#2 Updated by olemartin almost 5 years ago

It should be enough, but apparently it isn't :-)

I don't know much C, but from what I can understand from your code, it does something like this:
1. Generate a random value
2. Check if it's already used
3. If it's already used, add a value to the value and move along.

It seems like if 1. happens on two servers in the same second, the same value is generated. If you could seed the random generator with server startuptime or something, that would be great. They will never start up in the same millisecond.

Btw, how exactly do I use mod_magnet to generate unique cookies for my users?

#3 Updated by stbuehler almost 5 years ago

If you want you can try to add "srand(time(0));" in the main() function of lighty. (time() returns seconds, not milliseconds)

There is no check if a value is already used. It is just a random value.

And you should document how you reproduce the bug - i still don't really believe that this is likely to happen.

#4 Updated by olemartin almost 5 years ago

These are logentries from our haproxy server which logs the value of the cookie.
The ip-addresses are the ip-address of the client.
server01-01 and server01-02 are the names of our backend lighttpd servers


May  8 00:21:46 haproxy[3387]: 10.226.102.128:59914 [08/May/2009:00:21:45.993] server01-01 - cookiename=491b25ef46f5f4e8b63eae6 "GET / HTTP/1.1" 

May  8 00:21:46 haproxy[3387]:  10.226.111.95:40195 [08/May/2009:00:21:45.980] server01-02 - cookiename=491b25ef46f5f4e8b63eae6 "GET / HTTP/1.1" 

As you can see from the logs: Two different clients get the same cookievalue from two different servers.

#5 Updated by olemartin almost 5 years ago

It makes sense that rand default calls srand(time(0)) because that is exactly what happens in this case.

For a given seed (starting value), the sequence of numbers that rand() returns will always be the same.

If both servers are called with the same seed, ie time(0), they will generate the same sequence of numbers during the same second. I guess we will have to find something unique for the given lighttpd process. A combination of ip-address, pid, etc..

I don't know a lot of C, so I would highly appreciate a little guidance on how this should be done.

Thank you

#6 Updated by icy almost 5 years ago

The generation of the "unique" cookie is pretty weak.
But seeding rand properly is not so easy. Using time() could be enough for most cases as your processes are unlikely to start up at the same time.
The best way would be to use something like /dev/(u)random to seed rand() at startup and from time to time if available.

#7 Updated by peto almost 5 years ago

your processes are unlikely to start up at the same time

If you're running two lighttpd servers on the same machine, it's almost guaranteed.

Currently, srand is never called. This means that Lighttpd always starts with the same seed, at least with glibc:

RAND
If no seed value is provided, the rand() function is automatically seeded with a value of 1.

so rand() will always produce the same sequence of values.

It still seems reasonably unlikely that the same cookie would be produced, because:
- two new users would have to make a request in the same second;
- to the same url;
- while the random cookie is "in sync".

This is unlikely, but a few things make it possible:
- if you're making mostly FCGI/SCGI requests, the con->uri.path may always be eg. "/dispatch", eliminating the "same url" requirement;
- if your lighttpds are load balanced, the number of requests may average out to the same, causing the random cookie to periodically synchronize.

I'd recommend that, if it's supported by the OS, read 16 bytes from /dev/urandom on startup, just once per server. Feed this into the hash (not to srand()) as a salt everywhere a random value needs to be generated. This will almost totally guarantee the results are unique across servers.

This is probably more important in http_auth.c. In this case I'd strongly recommend replacing rand() with a secure, properly-seeded PRNG. The existing code may not exploitable, or very difficult, but rand() is a very poor basis for authentication tokens. Tip: pull yarrow+SHA1 out of tomcrypt; it's very simple, public domain code.

#8 Updated by stbuehler almost 5 years ago

  • Target version set to 1.4.23

#9 Updated by origo almost 5 years ago

Patch for current SVN to use /dev/random (or /dev/urandom) for entropy in both http_auth.c and mod_userauth.c

#10 Updated by stbuehler almost 5 years ago

  • Status changed from New to Fixed
  • % Done changed from 0 to 100

Applied in changeset r2524.

#11 Updated by stbuehler almost 5 years ago

You have to use rand() as you need different values in the same second.

#12 Updated by origo almost 5 years ago

Indeed you are correct. Thanks!

#13 Updated by brad@comstyle.com almost 5 years ago

origo wrote:

Patch for current SVN to use /dev/random (or /dev/urandom) for entropy in both http_auth.c and mod_userauth.c

for OpenBSD /dev/arandom should be used.

#14 Updated by stbuehler almost 5 years ago

I don't think we need "strong random" or "high-quality pseudo-random" - we just need some random data so different instances started in the same second use different data.

Also available in: Atom