package LIMS::Local::CSRF;
=begin
prevents cross-site request forgery and browser reload button (except following
a redirect); see cgiapp mailing list "CAP::Security::CSRF -- useful?"
=cut
use strict;
use warnings;
use base 'Exporter';
use LIMS::Local::Utils;
use vars qw($VERSION @EXPORT);
@EXPORT = qw(csrf_insert_token csrf_check_token);
$VERSION = '1.0';
sub csrf_insert_token {
my $self = shift;
my $token_name = shift || 'csrf_token';
# reuse the token that was submitted with the form; don't generate a new one
return if $self->query->param('csrf_token');
# generate a new token (not intended to be highly secure, or use random seed):
my $str = $self->session->param('_SESSION_ID') . time;
my $token = LIMS::Local::Utils::sha1_digest($str);
$self->tt_params( csrf_token => $token );
$self->session->param( $token_name => $token );
}
# returns true if POST'ed && query param token matches session token
# can set explicit token name, or accept default:
sub csrf_check_token {
my $self = shift;
my $token_name = shift || 'csrf_token';
my $session_token = $self->session->param($token_name); # warn $session_token;
my $query_token = $self->query->param('csrf_token'); # warn $query_token;
{ # ensure the form was POST'ed and session token == query token:
no warnings 'uninitialized'; # eg empty $session_token
return 0 unless $self->query->request_method eq 'POST'
&& $session_token eq $query_token;
}
$self->session->clear($token_name);
return 1;
}
1;