Beefy Boxes and Bandwidth Generously Provided by pair Networks
Don't ask to ask, just ask

Sessions with perl cgi

by wolis (Scribe)
on Oct 16, 2003 at 04:15 UTC ( #299647=perlquestion: print w/replies, xml ) Need Help??
wolis has asked for the wisdom of the Perl Monks concerning the following question:

Hi Monks,

Just wanting some of your opinions on session IDs.

I use code like this:

sub new_pid() { # generates a new pid.. return (time + ($$ ^ time)); }
Where $$ is the systems session ID (I belive), time is seconds since some time long ago, and ^ is.. well some maths function

I then carry this 'unique' number around with me (in form posts etc..) to determin if its the same session.

On some rare instances this can calculate two identical numbers so I was wondering if there was anything more robust for generating unique session IDs


___ /\__\ "What is the world coming to?" \/__/

Replies are listed 'Best First'.
Re: Sessions with perl cgi
by davido (Archbishop) on Oct 16, 2003 at 04:35 UTC
    jdtoronto's advice is good: CGI::Session. Be sure to look at for a description of that module and what it can do for you.

    Here is an excerpt from its POD:

    CGI-Session is a Perl5 library that provides an easy, reliable and modular session management system across HTTP requests. Persistency is a key feature for such applications as shopping carts, login/authentication routines, and application that need to carry data accross HTTP requests. CGI::Session does that and many more.

    I wanted to also point out a pretty good discussion on this subject (one of many that I found with the search button): Secure Session ID values. One thing I learned in that thread is that there are "session hijackers" out there looking to figure out the algorithm that creates a session ID so that they can hijack a session in progress and hopefully get things like credit card information. For that reason, it's a good idea to not use an algorithm that produces a session ID by following a predictable pattern. This is probably why MD5 hashing is such a popular component of secure session ID's.


    "If I had my life to do over again, I'd be a plumber." -- Albert Einstein
      To further explain why one should never, ever use anything guessable for session ids:

      A company of my acquaintance had a gallery system. People could upload pictures which, once approved, would appear in the gallery. The pictures that had not yet been approved were stored under the session name in a temporary (but publically-readable) directory. The session key was based on the current time and a simple incrementing counter.

      An enterprising porn operator noticed the system, and very quickly worked out how to access the public URLs of uploaded files. In a short period of time the company was inadvertantly hosting more than 3GB of, um, interesting pictures.

      This case is a combination of a few minor things not to do, but the total effect was potentially very damaging.

      bowling trophy thieves, die!

Re: Sessions with perl cgi
by jdtoronto (Prior) on Oct 16, 2003 at 04:28 UTC
    Personally I use CGI::Session which generates an MD5 hash which is 'carried around' or used in a cookie. I have never had a problem with it ( One site I did uses around 100K session ID's per month )


Re: Sessions with perl cgi
by sgifford (Prior) on Oct 16, 2003 at 06:05 UTC

    I agree that using something like CGI::Session is the best way to go, but if you want to roll your own or understand why this problem is harder than it looks, here's a little explanation. There are two goals to session IDs: uniqueness and difficulty to guess.

    You're pretty close on the uniqueness one; time and PID ($$) are the traditional way to get a unique token, since if your process is running at a particular time there can't be any other process with the same PID running. But I'm not sure why you're adding and XORing them together; something like join(".",time,$$) would work better, and be simpler. This technique breaks if the same PID is re-used in the same second---fairly unlikely to happen on a normal system with sequential PIDs, but it's more likely on a system with random PIDs, and can sometimes be forced to happen by an attacker, for example by making 65535 requests to your Web server in the same second. This technique will also fail if you're using persistent processes to handle Web requests, for example mod_perl.

    If you're storing sessions on the filesystem, the inode number of the session file is guaranteed to be unique. You can get that with stat. If sessions are in a database, the database can probably give you some kind of unique token (like an autoincrementing field). These techniques should always work, unlike PID+time, which at best will almost always work.

    As far as making session IDs hard to guess, your best bet is to use a truly random number, decide how hard you want to make your session IDs to guess, and then append that many random bits onto the end. Math::TrulyRandom along with the Entropy Gathering Daemon (or /dev/urandom if your OS supports it) are a pretty good way to get truly random numbers; using rand gives pseudorandom numbers that aren't suitable for protecting anything.

Re: Sessions with perl cgi
by IlyaM (Parson) on Oct 16, 2003 at 11:48 UTC
Re: Sessions with perl cgi
by v_thunder (Scribe) on Oct 16, 2003 at 13:25 UTC

    I generally use Data::UUID to generate unique IDs in my applications. Sometimes I use them as session IDs.


Re: Sessions with perl cgi
by deliria (Chaplain) on Oct 16, 2003 at 14:22 UTC
    Alternatively, if it's under apache on *nix you could install mod_unique_id to generate a unique id for you. According to Module mod_unique_id manual:

    Your website has one or more machines under your administrative control, together we'll call them a cluster of machines. Each machine can possibly run multiple instances of Apache. All of these collectively are considered "the universe", and with certain assumptions we'll show that in this universe we can generate unique identifiers for each request, without extensive communication between machines in the cluster.


    The UNIQUE_ID environment variable is constructed by encoding the 112-bit (32-bit IP address, 32 bit pid, 32 bit time stamp, 16 bit counter) quadruple using the alphabet A-Za-z0-9@- in a manner similar to MIME base64 encoding, producing 19 characters.

      However even the documentation for this module admits the reasonable possibility of producing a duplicate ID. I haven't studied the module, but an encoding scheme is by its very definition, decodable. Thus the ID produced by this system may well be susceptible to brute force attacks.

      I, for one, would be much happier to see a non decodable result, using say an MD5 hash.


Re: Sessions with perl cgi
by ChrisR (Hermit) on Oct 16, 2003 at 14:31 UTC
    Personally, I like to roll my own at least the first time around. Mainly, I do this for the educational value of trial and error and then comparing what I came up with to the standard ways of doing it. Here how I do it:
    • I take the elements returned by localtime
      ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime;
    • randomize the order
    • concatenate them
    • I then prefix a standard string ( I use a different prefix for each website)
    • I then md5_hex the whole thing
    Before storing the session id in MySQL, I confirm that it is unique. To date this has never returned a duplicate id.
      Before storing the session id in MySQL, I confirm that it is unique. To date this has never returned a duplicate id.

      I assuem this means you check if that id is still in your MySQL table. What do you do when a session times out? Keep it? I would have thought it would make for more efficient operation if the session were deleted when it was either closed or timed out.


        You are correct. I check to see if the session still exists in the table. When a session times out, the record is deleted. The record is also deleted if the user clicks "Logout". However, the users rarely if ever "Logout". When we first started using this, we had no session timeouts becuase we took for granted that the users would do as instructed and click "Logout" when they were done. OK, OK, so that was stupid on our part but we live, we learn, we improve, or we die. During the 4 months that we didn't have session timeouts, we never saw a duplicate session and still haven't. I know that doesn't mean that it never happened, but so far so good.
Re: Sessions with perl cgi
by jsegal (Friar) on Oct 16, 2003 at 18:04 UTC
    Others have suggested perhaps better ways to generate a session ID to guarantee uniqueness, and have pointed out the spoofing problem. One technique you can use to help ameliorate the spoofing problem is in addition to having hard to guess unique IDs, you can store the IP address of the client in with your session info (optionally even encoding it (hashed, presumably) in the session ID itself). Then, when you validate a new session, you can test that the incoming IP address matches that stored for your session. If it is a mismatch, you can either ignore/report the request, or abort the entire session as being "compromised."

    It is not foolproof (i.e. your attacker/spoofer could be coming from the same IP address as the spoofed session, or could even be spoofing the IP address), but it does add an extra layer of difficulty for the potential attacker, especially the attacker trying to randomly guess session IDs.


      This assumes that your clients are not accessing through a proxy. A proxy could introduce one of two "problems" to this...

      • Multiple clients come through the same proxy
      • One client can come through multiple proxies

      Situation 1 could happen with a large provider (AOL, for example). Situation 2 could happen with a farm of load balanced proxies / NAT / firewalls.

      Point being that this could generate some false positives (from a hack detection view), but if you can live with that, then yes, jsegal's suggestion does have merit :)


Re: Sessions with perl cgi
by ambrus (Abbot) on Oct 17, 2003 at 11:32 UTC
    If you use Apache, it might give your cgis some string like "P4-RKJhCUwEAABeK9DY" in $ENV{UNIQUE_ID}. This string is not quite random, but is different in each cgi invocation. This feature need not be enabled on your system, so you should check it before using it. See also
Re: Sessions with perl cgi
by monktim (Friar) on Oct 16, 2003 at 19:35 UTC
    How about using the address of your NIC and appending the time? That will give you a unique identifier that is hard to break.

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://299647]
Approved by jdtoronto
Front-paged by davido
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others musing on the Monastery: (3)
As of 2018-04-21 04:43 GMT
Find Nodes?
    Voting Booth?