> > > I working on a rather complex database cgi program and i've never done much work with user logins. Ideally I woudl love to set up a secure login which will verify passwords aggaints data stored in an SQL table. The modle I wish to use ie below. The area I need help with is the proper way to set and retrieve secure cookies. > > retrieve pw:login from form. > compare to stored password. > if match encrypt a string which is stored in the database then set the same string as a cookie with date and IP. > use this cookie to authenticate each subsiquent page until logout. > can someone point me to a good how to ? >
Security is always relative. Cookies are only "secure" (in one sense of the word) when passed over an https (like) connection, as your password should be too, otherwise anyone can sniff the password and be able to retrieve their own authenticated cookie. It sounds like you have a decent start, step 1 is easily handled with the CGI module. Comparing the password is easily handled with DBI to connect to your database. (Minor point, be sure to store the password in an encrypted/hashed way rather than directly.) Step 3 is a little odd, why are you storing the string in the database? Generally I don't think this is going to provide security, aka all I have to do is guess the string you stored and set a cookie manually, then I have an authenticated session. Generally the idiom goes something like, create a private key (aka a passphrase or something that no one else knows), take the key and some reproducible non-private information (such as the user name/id) and hash the two together. Provide the hash, and the information used to create it (NOT the private key!) in the cookie. Then during the requests check to see if the information provided back by the user from the cookie can be used to reproduce the same hash using the same private key as before. If the hash is reproduced then the user is authenticated. Assuming no one else has the private key, then the hash should be unique for the user and the private key should be non-guessable from the hash, generally if this holds an attacker can't produce a string that will authenticate correctly. In general using the IP address in this is not a good idea unless you know precisely what IP a particular user is going to come from. The complexity of your hash inputs can vary what you can do, aka adding expirations, etc. I don't take credit for this, the idiom is yanked from the Writing Apache Modules with Perl and C book from ORA, it provides an excellent discussion as well as code samples of how to implement this. I imagine there are also a number of modules available from CPAN that provide this functionality, Apache::Session rings a bell. http://search.cpan.org/~jbaker/Apache-Session-1.6/Session.pm#Tracking_users_with_cookies My recent implementation looks like this, the following is untested and I am not a security professional, Thoughts? http://danconia.org use constant CONFIG_AUTH_KEY => 'Secret passphrase goes here'; use Digest::SHA1; # # generate an authentication string that can be used to verify if # a user is who they say they are without a database lookup # sub authentication_string { my $self = shift; my $uid = $self->id; my $time = time; my $expires = 2592000; my $data = join(':', CONFIG_AUTH_KEY, $time, $expires, $uid); my $hash = Digest::SHA1::sha1_hex($data); return "uid=$uid time=$time expires=$expires hash=$hash"; } # # class method to verify an authentication string, returns # an exception on failure or the user id of the string on # success # sub check_auth_string { my $class = shift; my ($auth) = @_; unless (defined $auth) { die "Missing arg: auth string"; } # deparse auth string then check user cache my @auth = split(' ', $auth); my %auth; foreach my $element (@auth) { if ($element =~ /^(.+)=(.+)$/) { $auth{$1} = $2; } } foreach my $key ('uid', 'time', 'expires', 'hash') { unless ((defined $auth{$key}) && ($auth{$key} ne '')) { die "Cookie corrupt: $key"; } } my $testdata = join(':', CONFIG_AUTH_KEY, $auth{'time'}, $auth{'expires'}, $auth{'uid'}); my $testhash = Digest::SHA1::sha1_hex($testdata); unless ($testhash eq $auth{'hash'}) { die "Auth string corrupt"; } return $auth{'uid'}; } -- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED] <http://learn.perl.org/> <http://learn.perl.org/first-response>