#!/usr/bin/perl
#
# safe-form.pl
#
# CGI.pm Perl script demonstrating use of an HMAC
# to prevent user tampering of "hidden" form field values.
#
# Written by Advosys Consulting Inc., Ottawa
#
# Requires: Perl 5 with CGI.pm and Digest::HMAC modules
#
# Include perl modules:
use Digest::HMAC_SHA1;
use CGI qw/:standard/;
# Pick a secret password used to sign form variables:
# Keys should be as follows:
# - Picked at random and changed periodically
# - Be at least 20 characters (for SHA1)
$secretkey = 'soOperSeKretcOderINg';
# Print the MIME header before doing anything else:
print "Content-type: text/html\n\n";
print '
';
print 'Safe input form demo
';
# Assign some example values we don't want changed:
$userid = 'ktrout';
$credit_ok = 1;
$form_expires = '20051001:12:45:20';
# Display HTML form or check submission:
unless ( param('chaddr') ) {
# Get an HMAC for our 'hidden' field data:
$signature = sigHMAC( 'create', $secretkey, '$userid', '$credit_ok', '$form_expires');
print_form();
}
else {
# Validate signature
if ( sigHMAC( 'check', $secretkey, 'userid', 'credit_ok', 'form_expires' ) eq param('signature') ) {
print "\nThank you ", param('userid'), "
";
print "\nYour address information has been updated.";
} else {
print "\nERROR: 'Hidden' fields were tampered with!";
}
}
print "";
### SUBROUTINES:
#
sub print_form {
# Prints example HTML form with signature in a hidden field:
print<
END_TEXT
}
sub sigHMAC {
# Generates a SHA1 HMAC from a secret key and either a list of
# variables for a list of CGI.pm field names.
#
#
# Usage:
# sigHMAC( 'create', $secretkey, '$perlvar1' [, '$perlvar2' ] ... );
# or
# sigHMAC( 'check', $secretkey, 'ParamName1', [, 'ParamName2' ] ... );
#
my $mode = shift;
my $key = shift;
my @names = @_;
my $values = '';
my $fieldname;
# Create a new HMAC object with our key:
$hmac = $hmac = Digest::HMAC_SHA1->new($key);
# Join each variable name with it's value:
foreach $fieldname (@names) {
if ($mode eq 'create') {
$values .= $fieldname . eval $fieldname;
} else {
$values .= '$' . $fieldname . param($fieldname);
}
}
# Add our data:
$hmac->add( $values );
# Return a Base64 encoded HMAC for the data:
return $hmac->b64digest;
}