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

I'm trying to allow users to login to my script via an html form (Fields:username,password).

The database is a flatfile, and looks like this:

user1|cryptedpass1

This will be the only line in this password file as it's for the admin section.

Here is the code that I'm using to validate:

open(PASSWD, "$adminpasswddir/adminpasswd.db") || &dienice("Can't +open the file adminpasswd.db $!"); $admin_passwd = <PASSWD>; close(PASSWD); chop($admin_passwd); ($ausername,$apasswd) = split(/\|/,$admin_passwd); $test_passwd = crypt("$FORM{'password'}","k3"); if ($test_passwd eq "$apasswd" && $FORM{'username'} eq "$ausername +"){ &admin_main; } else { &dienice("Your username/password combination is incorrect. Ple +ase press your browsers back button and try again."); }

The problem that I'm having is that when I try to login, it says my password is incorrect. I noticed when putting some of the variables into the error page that when the script writes the password to the db it writes it as "k3LFRiJg/OOe" and when the script creates a variable with the entered admin password to be used to verify the password it creates a string which is identical with the addition of "Q" at the end "k3LFRiJg/OOeQ".
I know I'm not very advanced, but I just can't figure this one out I used the same line of code to create the password, so there should be no reason why this isn't working.

Thanks for all your continued support,
Titanic_Fanatic

Replies are listed 'Best First'.
Re: username/password validation
by Errto (Vicar) on Dec 19, 2004 at 21:00 UTC
    Here's my guess. The file that contains the id/password is a one-line file that does not have a newline character at the end. Therefore when you chop the line of text it removes the last letter from the encrypted password instead of the trailing newline, because there is none. The solution is to use chomp instead of chop. Open the file in a text editor to see if I'm right. I'll bet that final "Q" is there after all.
Re: username/password validation
by Cody Pendant (Prior) on Dec 19, 2004 at 23:05 UTC
    The use of crypt instead of something stronger, subs with ampersands, and "chop" instead of "chomp" makes this code look really old. It looks like Perl 4, am I right?


    ($_='kkvvttuubbooppuuiiffssqqffssmmiibbddllffss')
    =~y~b-v~a-z~s; print
Re: username/password validation
by titanic_fanataic (Acolyte) on Dec 20, 2004 at 01:19 UTC
    I thought that maybe you were right at first, but I am using chomp() and not chop(). It's weird thought, I just started to use "use strict;" and now what happens is if I try to submit with a completely wrong password, it will tell me that my username/password do not match, and heres where the weird part comes in. If i try to submit with my password followed by any characters, it still validates. I'm pretty sure this isn't supposed to happen.

    here is the code that I am using to verify the admin:

    sub verify_admin { my($admin_passwd,$ausername,$apasswd,$username); open(PASSWD, "$adminpasswddir/adminpasswd.db") || &dienice("Can't +open the file adminpasswd.db: $!"); $admin_passwd = <PASSWD>; close(PASSWD); chomp($admin_passwd); ($ausername,$apasswd) = split(/\|/,$admin_passwd); $username = "$FORM{'username'}"; my $cypassword = crypt("$FORM{'password'}","v6"); if ($cypassword eq "$apasswd" && $username eq "$ausername"){ &admin_main; } else { &dienice("Your username/password combination is incorrect. Ple +ase press your browsers back button and try again."); } }

    And here's the code that's being used to write to the admin password file:

    if ($FORM{'password'} eq "$FORM{'verifypassword'}"){ my $cpasswd = crypt("$FORM{'password'}","v6"); open(ADMINPASS, ">$adminpasswddir/adminpasswd.db") || &dienice("Ca +n't open the file adminpasswd.db $!"); print ADMINPASS "$FORM{'username'}\|$cpasswd"; close(ADMINPASS); open(USERS, "<$passwddir/users.db") || &dienice("Can't create the +file users.db $!"); close(USERS); print "Content-type: text/html\n\n"; #SUCCESS HTML } else { &dienice("Your passwords do not match. Please press your browsers +back button to fix the problem."); } exit; }

    If you need to see a copy of the script in full for reference, it can be downloaded from HERE

    Thanks again for all the help,
    Titanic_Fanatic

      From what you've told me, I can speculate that your password is 8 characters in length or longer. Crypt will only really take the first 8 characters and encrypt those; any extra characters are essentially lost in the transformation from plaintext to crypt()ed.

      12345 => 123456 | not equivalent 1234567 => 12345678 | not equivalent 12345678 => 12345678901 | equivalent # the actual perl function crypt($plaintext, $salt); # is more or less equivalent to this crypt( substr($plaintext, 0, 8), substr($salt, 0, 2) );
        Just to elaborate a bit. Unix has used DES for the crypt() function since at least the 1980s sometime. The DES crypt only depends on the first 8 characters. More recent systems use a MD5 hash for passwords. MD5 as an algorithm will allow arbitrary length passwords. That doesn't mean login code (in say a SSH program) won't have a limit (like 128 or 256 characters).

        If you move your site to use a database later you should know that the MySQL PASSWORD() function is sometimes used by website's for keeping site member's passwords hidden. When site's used this function for storing passwords the logins broke during the 4.0 to 4.1 upgrade. MySQL AB has documented that the PASSWORD function may change so you should use MD5() or SHA1() for your member login passwords.

        Use the Digest modules to get access to MD5 and SHA-1 in Perl. Using them is as easy as:
        use Digest::MD5 qw(md5_hex); $hashed = md5_hex($passwd);
        Then store the username and $hashed wherever you like.

        Also there has been some talk lately of probablistic attacks on MD5 password hashes which means given a MD5 hash it is not incredibly hard to find a password which will hash to the given hash. You may want to consider using SHA-1 instead. See http://passcracking.com/ and http://en.wikipedia.org/wiki/MD5#Security for more info.
      I tried the line of code that you gave me, and it still validates any string that contains the password and it can be proceeded by any number of other characters.

      I have a copy of the entire script HERE

      If that helps at all...

      Any other suggestions?

      Thanks again,
      Titanic_Fanatic