home | O'Reilly's CD bookshelfs | FreeBSD | Linux | Cisco | Cisco Exam  

Writing Apache Modules with Perl and C
By:   Lincoln Stein and Doug MacEachern
Published:   O'Reilly & Associates, Inc.  - March 1999

Copyright 1999 by O'Reilly & Associates, Inc.


   Show Contents   Previous Page   Next Page

Chapter 5 - Maintaining State / Storing State Information in SQL Databases
URI-Based Session ID Problems and Solutions

There are a couple of problems with URI-based session IDs. One is that because the session ID is tacked onto the end of the URI, relative URIs will no longer work correctly. For example, a reference to another Apache::Registry script named high_scores.pl located in the same directory will be resolved by the browser to something like this:


This is obviously not what you want, because the session ID has been replaced by the name of the script you want to run! Fortunately, the Apache API provides a simple fix for this. Store the session ID to the left of the script name rather than the right, like this:


To handle URIs like this, you can write a custom URI translation handler to modify the URI before it gets to the script. The full details of writing translation handlers are discussed in Chapter 7, Other Request Phases, but a simple module to accomplish this named Apache::StripSession is shown in Example 5-7. Briefly, the module checks whether the requested URI begins with something that looks like a session ID (eight hexadecimal digits). If it does, the handler strips out the session ID and uses subprocess_env() to place the ID in an environment variable named SESSION_ID. The handler replaces the request's original URI with the altered one and then returns DECLINED, telling Apache to pass the request onward to the standard translation handlers that will do the work of turning the new URI into a physical file path.

Example 5-7. A Translation Handler for Stripping Session IDs from URIs

package Apache::StripSession;
# file: Apache/StripSession.pm
use strict;
use Apache::Constants qw(:common);
sub handler {
   my $r = shift;
   my($junk, $session, @rest) = split '/', $r->uri;
   return DECLINED unless $session =~ /^[0-9a-h]{8}$/; 
    $r->subprocess_env('SESSION_ID' => $session);
   my $new_uri = join "/", "", @rest;
   return DECLINED;

Add this directive to srm.conf to activate Apache::StripSession:

 PerlTransHandler Apache::StripSession

With this translation handler in place, the get_session_id() no longer has to play games with the additional path information in order to recover the session ID. It can just read it from the environment. The other change to the subroutine is that the call to redirect() now places the session ID in front of the script name rather than after it:

sub get_session_id {
  return check_id($ENV{SESSION_ID}) if $ENV{SESSION_ID};
  my $session_id = generate_id();
  die "Couldn't make a new session id" unless $session_id;
  print redirect("/$session_id" . script_name());
  exit 0;

A more serious potential problem with URI-based session IDs is that under some circumstances it is possible for the session ID to "leak" to other sites via the HTTP referrer header (which, for historical reasons, is spelled "Referer"). If a page that has a session ID in its URI contains a hypertext link to another site, or even an image whose source is at another site, the page's URI, session ID included, will show up in the remote site's referrer log. Therefore, you must be careful not to include pointers to other sites in pages that use this method for storing session IDs. To get around this problem, you can put the session ID in a cookie, as the next section demonstrates.

   Show Contents   Previous Page   Next Page
Copyright 1999 by O'Reilly & Associates, Inc.