commit 73d50ec8871b9cfbb95b75338ae590d78bd91db7
parent 0327f3d8693661fc15a259ec2995dc75d6714069
Author: Samir Parikh <noreply@samirparikh.com>
Date: Fri, 25 Feb 2022 21:50:43 +0000
add message authentication check to cookie
Diffstat:
1 file changed, 29 insertions(+), 1 deletion(-)
diff --git a/hangman3.cgi b/hangman3.cgi
@@ -6,12 +6,14 @@
use IO::File();
use CGI qw( :standard );
use CGI::Cookie ();
+use MD5 ();
use warnings;
use strict;
use constant WORDS => '/usr/share/dict/hangman_words';
use constant TRIES => 6;
-use constant COOKIE_NAME => 'Hangman';
+use constant COOKIE_NAME => 'Hangman3';
+use constant SECRET => 'kiddo';
# retrieve the state
#my $state = get_state(); # $state is a hash reference
@@ -72,6 +74,7 @@ sub initialize {
sub save_state {
my $state = shift;
+ MAC($state, 'generate');
return CGI::Cookie->new (
-name => COOKIE_NAME,
-value => $state,
@@ -91,6 +94,7 @@ sub save_state {
sub get_state {
my %cookie = cookie( COOKIE_NAME );
return undef unless %cookie;
+ authentication_error() unless MAC(\%cookie, 'check');
return \%cookie;
}
@@ -207,3 +211,27 @@ sub pick_random_word {
chomp $word;
$word;
}
+
+sub MAC {
+ my ($state, $action) = @_;
+ return unless ref( $state );
+ my @fields = @{$state}{qw(WORD GUESSES_LEFT GUESSED GAMENO WON TOTAL)};
+ my $newmac = MD5->hexhash(
+ SECRET . MD5->hexhash( join '', SECRET, @fields )
+ );
+ return $state->{MAC} = $newmac if $action eq 'generate';
+ return $newmac eq $state->{MAC} if $action eq 'check';
+ return undef;
+}
+
+sub authentication_error {
+ my $cookie = CGI::Cookie->new(-name => COOKIE_NAME, -value=>'',-expires => '-1d');
+ print header(-cookie => $cookie),
+ start_html(-title => 'Authentication Error'),
+ h1(font({-color => 'red'}, 'Authentication Error')),
+ p('This application was unable to confirm the integrity of the',
+ 'cookie that holds your current score.',
+ 'Please reload the page to start a fresh session.'),
+ p('If the problem persists, contact the webmaster.');
+ exit 0;
+}