Okay so the way this works is the user authenticates via web form and generates a session ID as so:
sub session_open
{
my $sid;
my $user = shift;
if ( open(SEMA, "> ../sema/sess") )
{
flock SEMA, LOCK_EX;
do
{
$sid = generate_session_id();
}
while ( -d "$SDIR/$sid" );
my $sstr = "$user:$ENV{'HTTP_USER_AGENT'}";
write_file('>', "$SDIR/$sid", $sstr);
close SEMA;
}
return $sid;
}
The session ID is then passed to every page in the url, if the session file exists and checks out against his user agent and remote addr it allows the user to continue:
sub check_sid
{
my $sid = shift;
return 0 if $sid =~ /[^\w\d]/;
return 0 if !open(SID, "< $SDIR/$pid");
my ($user, $agent) = split /:/, <SID>, 2;
close SID;
return 0 if $agent ne $ENV{'HTTP_USER_AGENT'}";
return $user;
}
In the background I have a cron job running a script every 5 minutes expiring sessions 2 hours old:
foreach (<../session/*>)
{
unlink $_ if -M $_ > 0.08333;
}
Are there any flaws, unnecessary steps I am taking here? I figured use the user_agent and remote_addr as it would be harder to jack someones session ID that way.
Use CGI::Session. See also CGI::Application::Plugin::Session.
There is a race condition in
session_open.Does your session handling code allow any other session information to be written to the session file?
In
check_sid, you havemy $sid = shift;but you try to open"$SDIR/$pid".Even if you had correctly named the variable to be interpolated into the filename, there is the obvious flaw that you are not untainting the session id (that is, you are trusting unchecked input). Combine that with the fact that you are using the two argument form of
open, and interesting possibilities present themselves.In any case, there is no reason for anyone to write session handling code. The work has been done for you. Don’t reinvent the wheel.