=head2 get_session_id( [$user_salt] ) Generate a new, shiny, unique, unpredictable session id. Id is base64-encoded. The default is using two rounds of md5 with time, process id, hostname, and random salt. Should be unique and reasonably hard to guess. If argument is given, it's also added to the mix. Set $MVC::Neaf::X::Session::Hash to other function (e.g. Digest::SHA::sha224) if md5 is not secure enough. Set $MVC::Neaf::X::Session::Host to something unique if you know better. Default is hostname. Set $MVC::Neaf::X::Session::Truncate to the desired length (e.g. if length constraint in database). Default (0) means return however many chars are generated by hash+base64. =cut use Digest::MD5; use Time::HiRes qw(gettimeofday); use Sys::Hostname qw(hostname); use MIME::Base64 qw(encode_base64); # Premature optimisation at its best. # Should be more or less secure and unique though. my $max = 2*1024*1024*1024; my $count = 0; my $old_rand = 0; my $old_mix = ''; our $Host = hostname() || ''; our $Hash = \&Digest::MD5::md5_base64; our $Truncate; sub get_session_id { my ($self, $salt) = @_; $count = $max unless $count--; my $rand = int ( rand() * $max ); my ($time, $ms) = gettimeofday(); $salt = '' unless defined $salt; # using old entropy means attacker will have to guess ALL previous sessions $old_mix = $Hash->(pack "LaaaaLLLLaL" , $rand, $old_mix, "#" , $Host, '#', $$, $time, $ms, $count , $salt, $old_rand); # salt before second round of hashing # public data (session_id) should NOT be used for generation $old_rand = int (rand() * $max ); my $ret = encode_base64( $Hash->( pack "aL", $old_mix, $old_rand ) ); $ret = substr( $ret, 0, $Truncate ) if $Truncate and $Truncate < length $ret; return $ret; }; # finally, bootstrap the session generator at startap get_session_id();