#!/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<
Address line 1:
Address line 2:
City:
Prov:
Postal:
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; }