I am creating a website which will cater for several clients, each
of whom will have several users.
To keep life simple I will create a database for each client and
all the relevant stuff will go in there. There will also be a master
database that stores only the information that is needed to get the
user to the right database at login.
The users will be given sessions (stored in cookies) which say not
only who they are but also which database they should connect to. Once
the database has been determined the session_id and session_secret
will be used to check that the user is allowed.
The attached code is my attempt to prevent tampering of that
cookie. It is cut back so that only the relevant bits are presented. I
am fairly sure that it is secure but I cannot be sure.
Please could you look at this code and see if there are any holes. Thank you.
#!/usr/bin/perl
use strict;
use warnings;
use String::CRC::Cksum qw(cksum);
use Crypt::CBC;
# Utility function.
sub display {
my ( $first, $second ) = @_;
print ' 'x( 16 - length $first ), "$first: '$second'\n";
}
my $database_id = 1234;
my $session_id = 5678;
my $session_secret = join '', 'a'..'z';
# Create the input.
my $in = join ':', $database_id, $session_id, $session_secret;
display "Input", $in;
my $cipher_text = my_encrypt( $in );
display "Encrypted token", $cipher_text;
# $cipher_text =~ s/a/b/g; # <= uncomment to muck up the encryption.
# display "Altered token", $cipher_text;
my $out = my_decrypt( $cipher_text );
display "Output", $out;
display 'Result', $in eq $out ? "Good" : "Bad";
##############################################
sub my_encrypt {
my $input = shift || die;
# Calculate the checksum and then prepend it to the token.
my $cksum = cksum( $input );
my $token = join ':', $cksum, $input;
display "Token", $token;
# Encrypt the token to hex.
my $cipher = get_cipher();
my $hex_token = $cipher->encrypt_hex( $token );
return $hex_token;
}
sub my_decrypt {
my $input = shift || die;
my $cipher = get_cipher();
my $cksum_token = $cipher->decrypt_hex( $input );
display "Decrypted token", $cksum_token;
unless ( $cksum_token ) {
warn "Error decrypting";
return 0;
}
# Extract the checksum and then check it.
my ( $cksum, $token ) = split /:/, $cksum_token, 2;
# If the checksum is correct.
return $token if defined $cksum
&& $token
&& $cksum =~ m/^\d+$/
&& cksum( $token ) == $cksum;
# If it is not correct then complain.
warn "Checksum is wrong.";
return 0;
}
sub get_cipher {
my $system_secret = 'top secret';
return Crypt::CBC->new
( {'key' => $system_secret,
'cipher' => 'Blowfish' }
) || die;
}
I know that there are modules such as
Apache::Cookie::Encrypted but I want to be able to put the encrypted token elsewhere and so want a more flexible home grown solution.
--tidiness is the memory loss of environmental mnemonics
-
Are you posting in the right place? Check out Where do I post X? to know for sure.
-
Posts may use any of the Perl Monks Approved HTML tags. Currently these include the following:
<code> <a> <b> <big>
<blockquote> <br /> <dd>
<dl> <dt> <em> <font>
<h1> <h2> <h3> <h4>
<h5> <h6> <hr /> <i>
<li> <nbsp> <ol> <p>
<small> <strike> <strong>
<sub> <sup> <table>
<td> <th> <tr> <tt>
<u> <ul>
-
Snippets of code should be wrapped in
<code> tags not
<pre> tags. In fact, <pre>
tags should generally be avoided. If they must
be used, extreme care should be
taken to ensure that their contents do not
have long lines (<70 chars), in order to prevent
horizontal scrolling (and possible janitor
intervention).
-
Want more info? How to link
or How to display code and escape characters
are good places to start.