Bug #1977
closedmod_usertrack generates same cookie value on different lighttpd instances
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?
Files
Updated by stbuehler over 15 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.
Updated by olemartin over 15 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?
Updated by stbuehler over 15 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.
Updated by olemartin over 15 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.
Updated by olemartin over 15 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
Updated by icy over 15 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.
Updated by peto over 15 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.
Updated by origo over 15 years ago
- File http_auth_mod_usertracks_entropy.patch http_auth_mod_usertracks_entropy.patch added
- Target version changed from 1.4.23 to 1.5.0
Patch for current SVN to use /dev/random (or /dev/urandom) for entropy in both http_auth.c and mod_userauth.c
Updated by stbuehler over 15 years ago
- Status changed from New to Fixed
- % Done changed from 0 to 100
Applied in changeset r2524.
Updated by stbuehler over 15 years ago
You have to use rand() as you need different values in the same second.
Updated by brad@comstyle.com over 15 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.
Updated by stbuehler over 15 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