Thathom has asked for the wisdom of the Perl Monks concerning the following question:

Hello,

I'm trying to create a self contained little system that stores Usernames and Passwords to allow people to login and have their Username and Password stored in a cookie for validating authenticity in various functions.

I've created this.. and I'm pretty sure it's ok but I was wondering if those that are far more experienced than me had any suggestions. It's only for a mini site but I wanted to make sure user passwords were not seen in the cookie AND that some form of randomness was involved with the checking. (I've commented how it works for real newbies incase they were interested in understanding it). I've missed out all the Opening of Files and Writing of the Cookies. I'm just concerned about what's being stored where and how it's working.

It's a complete script and will run on it's own and on each refresh it will show what it's doing.

#!/usr/bin/perl #----------------------------------- use CGI::Carp "fatalsToBrowser"; use strict; print "Content-type: text/html\n\n"; print "<html><body><font face=verdana><b>Testing</b><br>"; #First, lets pretend user has signed #up and is using the following username #and password #---------- my $username = "monkey"; my $password = "platform"; #They're stored in a file... #---------- print qq| <b>Signing Up</b> <ol> <b>Stored in File:</b><br> $username<br> $password<br> </ol> |; #Now lets pretend the User is logging #in to their account. Validate that #the username and password they enter is #the same as that in the file. If it is, #then create a special validating code so #that it can be stored in a cookie and compared #back to the account when required. #---------- my $code; my $string = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ +0123456789"; RandomString($string); for (my $i = 0; $i < length($password); $i++) { my $pos = index($string,substr($password,$i,1)); $code .= "$pos,"; } #All done, store the $code in the account file #along with the username and password and write #a cookie storing the username and $string in it #---------- print qq| <b>After First Login:</b> <ol> <b>Stored in File:</b><br> $username<br> $password<br> $code<p> <b>Stored in Cookie</b><br> $username & $string<br> </ol> |; #Now, nobody can see the password from the cookie #and each time the User logs in, it will create a brand #new code and string for the cookie. #Validating what's in the cookie against the User #account. Pretend we've opened the User Account and #have accessed the cookie. #---------- my @DECRYPT = split('[,]',$code); my $cookiepassword; foreach(@DECRYPT){ $cookiepassword .= substr($string,$_,1); } #If $cookiepassword = $password on account then #all is ok! print qq| <b>Validating Cookie against Account</b><br> <ol> Account Password is : $password<br> Cookie Password is : $cookiepassword<br> Obtained by cross referencing:<br> $code with<br> $string<br> </ol> |; print "</font></body></html>"; ########## sub RandomString { ########## my ($tmp,$y); my $len = length($_[0]); for(my $i = 0; $i < $len; $i++){ $y = $i + rand($len-$i); $tmp = substr($_[0],$i,1); substr($_[0],$i,1) = substr($_[0],$y,1); substr($_[0],$y,1) = $tmp; } return $_[0]; } #End of Script #----------------------

Any suggestions on improvement are most welcome (without modules please).

Edited by Chady -- added readmore and paragraph tags.

Replies are listed 'Best First'.
Re: User, Encrypting Passwords and validating
by cees (Curate) on Feb 07, 2004 at 18:09 UTC

    You seem to be doing a lot of work fudging up the password, without any real gain. Your scheme could be simplified by just passing a random string to the user and storing that same random string in the database along with the username and password.

    What you seem to be attempting is usually called ticket based authentication. The user provides a username and password, and if authenticated, you give them a ticket that will allow them back in without needing to enter their password again.

    But you are missing a critical piece in order to make it secure. It is absolutely vital that the ticket can be expired at some point. Otherwise an attacker could sniff the ticket, or pull it from someones cookie file, and use it at any time in the future to gain access without a password.

    - Cees

      Yeah good point actually. I guess im trying to never store the users password in either the file or in the cookie. Just trying to figure out now to do it, so if anyone hacks either the cookie or the file, they'll never end up getting the original password. Thanks! that's helped
      ThAtH0M
        I guess im trying to never store the users password in either the file or in the cookie.

        That is usually accomplished by only storing a one way hash of the password. This is how the Unix passwd/shadow file stores passwords. You can check to see if a supplied password is valid by hashing it again and comparing it against what is stored.

        if (crypt($password, $storedpwd) ne $storedpwd) { die "Sorry...\n"; } else { print "ok\n"; }

        You mentioned that you don't want to use external modules, so I showed an example using the built in 'crypt' function (see 'perldoc -f crypt' for more info), but it would be more secure to use SHA1 or MD5 hashes.

        - Cees

Re: User, Encrypting Passwords and validating
by Abigail-II (Bishop) on Feb 07, 2004 at 17:51 UTC
    If all you do is "encrypt" the password in a cookie, and let the cookie all that's needed for authentication, using of a cookie is hardly any more secure than sending the password. If an attacker snoops the cookie, he/she can pretent to be the user. About the only protection this cookie scheme offers is towards the user - if she uses the same password for different sites, an attacker can't use the cookie (assuming the attacker doesn't know the decryption key) to log in as the user to a different site.

    Off course, discussing these kinds of schemes has hardly anything to do with Perl. The level of protection offered doesn't depend on the language you are creating the cookies in.

    Abigail

Re: User, Encrypting Passwords and validating
by coreolyn (Parson) on Feb 07, 2004 at 18:30 UTC

    I'd crypt the username password before storing into a file. One exploit and your entire userbase could be compromised.