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;