change_session_id
It is considered good security practice, and is a requirement of a number of established security standards, to change session ID on any change of privilege level. For starters you should consider doing this on user login, and possibly at any other time a user has some privilege added or removed.
Session destruction
Destroying a session in Dancer2 has always been possible using Dancer2::Core::App/destroy_session like so:
app->destroy_session;
Session destruction by its very nature causes the session ID to change since the server instructs the client to forget the session ID, send it a new session ID and also destroys any session data held on the server. This is considered a "good thing" when a user logs out of an application but it is not very useful when a user logs in and you want to keep existing session data such as cart products.
change_session_id
Dancer2::Core::App/change_session_id to the rescue!
If you are using version 0.610 or later of Dancer2::Plugin::Auth::Extensible
to handle authentication and authorisation then you already have
change_session_id
called on successful login. If you are using some
other solution then you want to do something like this:
post '/login' => sub { my $username = body_parameters->get("username"); my $password = body_parameters->get("password"); if ( my_authentication_check( $username, $password ) ) { # login successful app->change_session_id; } };
You might also want to consider calling change_session_id
after successful
password change.
The gory details
This part is particularly relevant to implementors of session engines.
Native session engine support
All session engines should implement the private method _change_id
which is called like so:
$session_engine->_change_id( $old_id, $new_id )
Where $old_id
and $new_id
are the old and new session IDs respectively.
The session engine should do whatever is necessary for the ID change to be successful such as changing the key used in the session storage.
All file-based session engines including Dancer2::Session::YAML and
Dancer2::Session::JSON get native support for change_session_id
since they consume the Dancer2::Core::Role::SessionFactory::File which
provides _change_id
.
Non-native fallback support
If you have a session engine that doesn't implement _change_id
then don't
worry: we added a fallback mechanism to Dancer2 which does this:
my $session = $self->session; # grab data, destroy session and store data again my %data = %{$session->data}; # destroy existing session $self->destroy_session; # get new session $session = $self->session; # write data from old session into new # Some engines add session id to data so skip id. while (my ($key, $value) = each %data ) { $session->write($key => $value) unless $key eq 'id'; } # clear out destroyed session - no longer relevant $self->clear_destroyed_session;
This fallback mechanism will hopefully be removed some time in the future.
Further reading
OWASP Session Management Cheat Sheet.
Author
This article has been written by Peter Mottram for the Perl Dancer Advent Calendar 2016.
Copyright
No copyright retained. Enjoy.
2016 // Peter Mottram (SysPete) <peter@sysnix.com>