http://qs1969.pair.com?node_id=316641

rkg has asked for the wisdom of the Perl Monks concerning the following question:

Hi -- Can I be assured the following code generates a unique cookie id in a mod_perl environment?

ToBase62 just converts an int to base62 representation(A-Z,a-z,0-9).

Do I need to worry about different length pids?

Thanks

rkg

sub generate_id { my $id = $ToBase62->(time) . $ToBase62->($$) . ToBase62->( rand($$ +) ); return $id; }

Replies are listed 'Best First'.
Re: unique cookie id?
by cees (Curate) on Dec 23, 2003 at 17:51 UTC

    Since you are using mod_perl, you might as well use apache's mod_unique_id to generate unique IDs for you. From the docs:

    This module provides a magic token for each request which is guaranteed to be unique across "all" requests under very specific conditions. The unique identifier is even unique across multiple machines in a properly configured cluster of machines. The environment variable UNIQUE_ID is set to the identifier for each request.

    Every request will have $ENV{UNIQUE_ID} set to a unique value.

    If for some reason you do not have access to use this module, then you can look at the source code for the implementation that they use to generate a unique ID in an apache environment (remember that in mod_perl2 you may have to deal with a threaded environment).

    Update: Just remembered, have a look at Apache::Session::Generate::MD5 for a mechanism similar to yours that Apache::Session uses to generate Session IDs. I would still recommend going with mod_unique_id, but this could be an option for you as well. Please note that you do not need to use Apache::Session in order to use Apache::Session::Generate::MD5...

    - Cees

Re: unique cookie id?
by hardburn (Abbot) on Dec 23, 2003 at 16:32 UTC

    IIRC, the PID under mod_perl will be the PID of whatever Apache thread you're running under. So the $ToBase62->($$) part will often be the same.

    This code makes me nervous, because it gives away the PID of the process. This is a small bit of information to give to an attacker, but I like to know that an attacker has as little information about my system as possible. Further, PIDs are not as random as they appear (unless you know your system does otherwise, such as OpenBSD or a patched version of Linux).

    For generating session IDs, I usually use Data::UUID. It's not guarenteed to be truely random (though if you want that it shouldn't be too difficult to patch or subclass), but it is guarenteed unique for a reasonable ammount of time.

    ----
    I wanted to explore how Perl's closures can be manipulated, and ended up creating an object system by accident.
    -- Schemer

    : () { :|:& };:

    Note: All code is untested, unless otherwise stated

      Add to the fact that if you have an SMP machine, it is easily possible for two requests to be processed at the same time on a busy site. Easily possible for the time() to be the same value that is.

      Be afraid.. be very afraid ;)

      Update: Added the middle sentence.


      Play that funky music white boy..
Re: unique cookie id?
by duct_tape (Hermit) on Dec 23, 2003 at 18:26 UTC

    As a well tested and proven module, I think that you may want to look into how Apache::Session generates ids. The below code was taken directly from Apache::Session::Generate::MD5.

    Digest::MD5::md5_hex(Digest::MD5::md5_hex(time(). {}. rand(). $$))

    It basically takes an MD5 checksum of a MD5 checksum of a string like this 1072203122HASH(0x80f915c)0.43483996817758877220. It generates a 32 character long string like af68382107551b68473e6a7836ab372e. I would consider that to be pretty unique and unguessable.

Re: unique cookie id?
by jdtoronto (Prior) on Dec 23, 2003 at 19:25 UTC
    The subject comes up here fairly regularly. But you have had some good advice already. Let me add a couple of comments:
    1. It is never a good idea to use a PID, GID, or machine related value as even a seed for an ID. It can easily result in identical values being generated. In fact I tested this. Using a dual PIII-933 machine with mod-perl and an ID based on pid and time as you are proposing, I got the same ID produced on 31 ocassions out of 2,350,000 requests and on one ocassion got the same ID 4 times in succession. Very very insecure!
    2. Using Apache::Session or CGI::Session (I prefer the latter - it is much more flexible and works much the same - it is modelled on the former.) using MD5 hashes is good. Even better is using SHA-1 digest pattern which is 160 bits long rather than the 128 bits of the MD-5 digest.
    3. You should change the cookie-id regularly - if you can. If you tie the value to your session then make sure the session does not persist across browser sessions. If it does, then you should track authentication on top of that.
    4. I take the MD5 session value from CGI::Session, concatenate the TIME with it and the username then I encrypt the whole lot using Blowfish. That way I can decrypt on the next request and make sure that the time value is the same as that which I have in the session record so that I can be sure that requests are being handled serially. If I get a time skip then I have either lost a request or a response, if this occurs more than once in 64 request/response cycles then either their is something funny going on or the client has an extremely poor connection!
    Whatever you choose, good luck!

    jdtoronto

Re: unique cookie id?
by cLive ;-) (Prior) on Dec 23, 2003 at 17:49 UTC
    I tend to use this:
    use Digest::MD5 my $cookie_id = Digest::MD5::md5hex($$.time.$ENV{'REMOTE_ADDR'});

    With the hash always being 32 chars long. Works for me.

    Though maybe $$ under mod_perl is irrelevant here. Hmmm

    cLive ;-)

      Digest::MD5::md5hex($$.time.$ENV{'REMOTE_ADDR'});

      This won't be unique if you get two requests to the same Apache process from the same IP in under a second. Something that's fairly likely to happen in many environments I'm afraid :-)

        Unlikely in our instance though :)

        cLive ;-)

Re: unique cookie id?
by adrianh (Chancellor) on Dec 23, 2003 at 22:06 UTC
    Can I be assured the following code generates a unique cookie id in a mod_perl environment?

    Nope.

    For example, it's perfectly feasible that two requests could be processed in under a second on a single Apache process, and the same random number come up twice.

    Also, since you're not separating the values you use with a delimiter you can get the same string from different values, e.g.:

    $ToBase62->(time) $ToBase62->($$) ToBase62->( rand($$))
    1234 567 89
    12345 678 9

    both give the same ID.

    Personally I tend to use Data::UUID for creating unique IDs.

      Many thanks. Yes, I couldn't put my finger on it, but it was the lack of delimiter that was irking me. Thanks for the clear chart.

      I've heeded the wise advice here and am going with

      Digest::MD5::md5_hex(Digest::MD5::md5_hex(time(). {}. rand(). $$))