http://qs321.pair.com?node_id=256208

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

Hi Monks,

I'm working on a cgi script. Users must log in with a username and password, which my script sends to an LDAP server for authentication.

After the initial login, I want users to be able to go about using the script without having to log in again, e.g., I want to set a cookie. The cookie should contain the username and password of the user, and each time the script is called thereafter the cookie will be retrieved and checked against the LDAP server. But I don't want to set a cookie with the password in clear text, so I need to encrypt it somehow. I can't use a way-one encryption like an MD5 hash as I need to be able to decrypt the password to send to the LDAP server. Any suggestions on how to proceed? Specifically, encryption types and perl modules to use?

Replies are listed 'Best First'.
Re: Two-Way Password Encryption
by hardburn (Abbot) on May 07, 2003 at 14:19 UTC

    Don't put the username/password combo in the cookie, encrypted or not. Instead, on the intial login, get their username/password and do the authentication. Once authenticated, put their username in a database paried with a unique session ID (I usually use Data::UUID for that) and send the session ID in the cookie. On subsequent entries, you check the session ID against your database. Keep another script in a crontab that deletes old session IDs from the database.

    There are various authentication modules in the Apache:: namespace, but most of them only work if you're running mod_perl on Apache.

    ----
    I wanted to explore how Perl's closures can be manipulated, and ended up creating an object system by accident.
    -- Schemer

    Note: All code is untested, unless otherwise stated

      There are various authentication modules in the Apache:: namespace, but most of them only work if you're running mod_perl on Apache.

      However, for the technique you are describing you can use Apache::Session, which is usable for CGI scripts.

      Then you can use Data::UUID for creating the session id. Nice module by the way - hadn't heard of it till now - hardburn++

      -- Joost downtime n. The period during which a system is error-free and immune from user input.
Re: Two-Way Password Encryption
by Abigail-II (Bishop) on May 07, 2003 at 14:58 UTC
    Note that if you store something in a cookie, and all that's required for authentication is to echo back what's in the cookie, it hardly matters whether you store an encrypted password, or a random number. You will be vunerable against session hijacking. Someone able to snoop the connection between the client and the server can intercept the cookie, and hence pretent to be the person that is logged in.

    You might want to consider using an encrypted channel instead.

    Abigail

      To simplify this response...++ by the way :) authenticating by any method over SSL is preferrable.

      Speaking of which does anyone know where I can get a good tool for making my own certificates. I work on mostly internal stuff, so I don't have much use for buying one from a certificate authority. The one that comes with mod_ssl is kind of clunky if you ask me.

      smiles

        Give openSSL a try for self-signed certificates. It works on many platforms and has all the features you might need for this task (and then some...)

        Best regards

        -lem, but some call me fokat

        At the apache-ssl website, they have these instructions on how to create a test certificate. I did it today as a matter of fact.
        Here's the dirt just in case you don't want to follow the link:
        how do I create a test certificate?
        
        Step one - create the key and request:
        
          openssl req -new > new.cert.csr
        
        Step two - remove the passphrase from the key (optional):
        
          openssl rsa -in privkey.pem -out new.cert.key
        
        Step three - convert request into signed cert:
        
           openssl x509 -in new.cert.csr -out new.cert.cert -req -signkey new.cert.key -days 365
        
        

        Replace the word new-cert with a variable, and you could easily turn this into a quite simple script to spit out certificates as fast as the script will run.

        This is obviously just a way to create certificates, making your web server of choice use them, is another animal.


        Very funny Scotty... Now PLEASE beam down my PANTS!
Re: Two-Way Password Encryption
by tjh (Curate) on May 07, 2003 at 14:44 UTC
    Maybe re-validating the user against the LDAP data is required for each page view for a reason I'm not getting. However, if the initial verification is satisfactory for the user's session, and you are just looking to maintain state and session between page views, you might want to look at:

    HTH

Re: Two-Way Password Encryption
by Willard B. Trophy (Hermit) on May 07, 2003 at 15:00 UTC
Re: Two-Way Password Encryption
by sschneid (Deacon) on May 07, 2003 at 14:38 UTC
    Some (untested) code...

    Set the cookie containing the username and an encrypted key (the password + $key):
    use Crypt::CBC; my $key = 'kjhAG43asoiudy3kjq43ajhali87LOljkYilKH84yiHLkjklasjsd98fu'; my $cipher = new Crypt::CBC($key,'Blowfish'); my $crypt = $cipher->encrypt($password); $cgi = new CGI; my $auth = "$user,$crypt"; $cookie = $cgi->cookie ( -name => 'hostauth', -value => $auth ); print $cgi->header (-type => 'text/html', -cookie => $cookie);
    And then, whenever you want, you can decrypt the key in the cookie (using the same $key) and send it along to the LDAP server:
    use Crypt::CBC; my $key = 'kjhAG43asoiudy3kjq43ajhali87LOljkYilKH84yiHLkjklasjsd98fu'; my $cipher = new Crypt::CBC($key,'Blowfish'); my $auth = $cipher->decrypt($cookie); # Send the $auth to the LDAP server...
    -s.
Re: Two-Way Password Encryption
by nite_man (Deacon) on May 07, 2003 at 14:55 UTC
    You can use kerberos - the Network Authentication Protocol. There is a Perl interface to the Kerberos API - Authen::Krb5.
          
    --------------------------------
    SV* sv_bless(SV* sv, HV* stash);