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

Next in line--CGI cookies.. I tried writing a very basic login script (which works) and tried my first attempt at setting/using cookies (which I'm still confused about). You need to set the cookies in with the HTTP header, says CGI docs, but if that's the case how can you print out a form, ask for details, THEN give them a cookie if they login? If you need to send cookies with the header, it has to already exist before the script is run the first time..that's why I'm confused.

The partial script below is trying to say (If there is a cookie, print "you're in" otherwise print the form and wait for the user to login correctly then set their cookie).

When the script is run the first time it says 'bad cookie' but even if they login correctly it says 'bad cookie'..maybe the cookie isn't being set at all. Can someone give me a hand with this?

print header, start_html; if ( cookie('sessionID') ) { print "You're in!"; print cookie(); } else { print "BAD COOKIE!<br>"; print start_form(), table( Tr( td("Username:"), td( textfield( -name => 'username', -size => '15' ) ) ), Tr( td("Password:"), td( textfield( -name => 'password', -size => '15' ) ) ), Tr( td( submit('send') ), ), end_form, ); if (param) { use Digest::MD5 qw(md5 md5_hex md5_base64); my $user = param('username'); my $passold = param('password'); my $pass = md5_hex($passold); #encrypt if ( exists $login{$user} ) { if ( $login{$user} == $pass ) { print "Good!<br>"; my $contents = join("::", $user, $pass); my $cookie= cookie( -name => 'sessionID', -value => "$contents", -expires => '+1h', -secure => 1 ); print "\$contents: $contents<br>"; print "$cookie<br><br>"; print "Your cookie should have been set<br>"; } else { print "Bad password!<br>"; } } else { print "Username not found!<br>"; } print "You typed: $user => $pass<br>"; print "<br><br>"; foreach ( keys %login ) { print "$_ => $login{$_}<br>"; } } }


"Age is nothing more than an inaccurate number bestowed upon us at birth as just another means for others to judge and classify us"

sulfericacid

Replies are listed 'Best First'.
Re: yummm...cookies, anyone?
by antirice (Priest) on Aug 04, 2003 at 02:16 UTC

    Just do everything prior to printing out the header. It'd go something like this:

    Check for the cookie. If present and valid, print the header and respond as appropriate. If no cookie, then check for form data being submitted. Verify the data and return the cookie with the header if appropriate. If no form data that is valid, print the header without a cookie and show the form.

    Just be aware that browsers can be set to not allow for cookies. Also, don't store anything important in them (i.e. username and password when using it can allow them to get cc numbers...etc.). I think merlyn has an article on it at his site.

    antirice    
    The first rule of Perl club is - use Perl
    The
    ith rule of Perl club is - follow rule i - 1 for i > 1

      I put the print header(cookie..) inside the first loop and put a normal print header in the other loop where the form is to be printed. It didn't work at first when I used $cookie because $cookie can't be defined until they login so I used if ( cookie('sessionID') ) { which seems to work.

      Now something weird is happening. When you click the login button it changes the url from http://sulfericacid.perlmonk.org/login to http://sulfericacid.perlmonk.org/%2Flogin, which of course can't be found. Why is the cookie changing the url?

      You said I shouldn't store passwords inside the cookies, is this ALWAYS a rule or is it okay if you encrypt the password?

      Thanks

      if ( cookie('sessionID') ) { print header(-cookie=>'sessionID'), start_html; print "You're in!"; print cookie(); } else { print header, start_html; print "BAD COOKIE!<br>"; print start_form(), table( Tr( td("Username:"), td( textfield( -name => 'username', -size => '15' ) ) ), Tr( td("Password:"), td( textfield( -name => 'password', -size => '15' ) ) ), Tr( td( submit('send') ), ), end_form, ); if (param) { use Digest::MD5 qw(md5 md5_hex md5_base64); my $user = param('username'); my $passold = param('password'); my $pass = md5_hex($passold); #encrypt if ( exists $login{$user} ) { if ( $login{$user} == $pass ) { print "Good!<br>"; my $contents = join("::", $user, $pass); my $cookie= cookie( -name => 'sessionID', -value => "$contents", -expires => '+1h', -secure => 1 );


      "Age is nothing more than an inaccurate number bestowed upon us at birth as just another means for others to judge and classify us"

      sulfericacid

        First thing first: print header(-cookie=>'sessionID') prints a header like this:

        Set-Cookie: sessionID Date: Mon, 04 Aug 2003 02:50:03 GMT Content-Type: text/html; charset=ISO-8859-1

        Which I believe is not what you were hoping for. Use cookie() to return something that will work. Now here is your program in pseudocode:

        1. Check for a cookie by the name of sessionID. If it is something that can be evaluated as true, welcome them like your long lost puppy named Cocoa.
        2. Print a header which is the only place from which one may set a cookie and start the html. Proceed as if nothing that should set off fireworks in your mind just happened.
        3. Print a form.
        4. Check to see if any parameters exist. If they do:
          1. import md5, md5_hex, and md5_base64 from Digest::MD5. Of course, only md5_hex is used but he needs friends :)
          2. Read in and set variables for parameters username and password, not bothering to see if they're set to anything.
          3. Produce an md5_hex hash of the password given.
          4. Check to see if a login entry exists for the username supplied and check to see if the entry matches the md5_hex hash of the password provided.
          5. If so, welcome them to valhalla! (...even though we just printed out a form asking for login credentials). Create a cookie whose contents will never be placed in the header since the header has already been written to the browser.
          6. Drink a beer, this snippet is done.

        You may notice the emphasis on part 2 and part 4.5. The cookie MUST be placed within the header. Check everything prior to printing the header.

        Update: Ugh...sarcasm...*sigh*. So you know I'm not a bad guy:

        my %options; my $cookie; if (cookie('sessionID') && checkSessionID(cookie('sessionID'))) { $cookie = cookie(-name => 'sessionID', -value => cookie('sessionID'), -expires => '+1h', -path => '/'); } # you may notice I don't use -secure=>1...this is because # you require an ssl certificate to be present for the # cookie to work (although not all browsers really follow it) elsif (param('username') && param('password') && checkUserPass(param(' +username'),param('password))) { $cookie = cookie(-name => 'sessionID', -value => makeCookie(param('username'),param('pas +sword)), -expires => '+1h', -path => '/'); } $options{"-cookie"} = $cookie if $cookie; print header(%options),start_html; # now if $cookie is set, print stuff as if they're logged in

        Hope this helps.

        antirice    
        The first rule of Perl club is - use Perl
        The
        ith rule of Perl club is - follow rule i - 1 for i > 1

Re: yummm...cookies, anyone?
by edoc (Chaplain) on Aug 04, 2003 at 04:22 UTC

    the two things I see, are the setting of secure and not of path.

    The urls you have do not look like they go over SSL, but:

    If a cookie is marked secure, it will only be transmitted if the communications channel with the host is a secure one. Currently this means that secure cookies will only be sent to HTTPS (HTTP over SSL) servers.

    If secure is not specified, a cookie is considered safe to be sent in the clear over unsecured channels. http://wp.netscape.com/newsref/std/cookie_spec.html

    I believe that some/all versions of IE will not save a cookie if the path is not specified in the cookie.

    cheers,

    J

Re: yummm...cookies, anyone?
by Cody Pendant (Prior) on Aug 04, 2003 at 04:15 UTC
    Just to say, I used CGI::Session for this the other day sulferic, and I was very surprised how easy it was to get going with.

    There were a couple of typos/errors in the examples on CPAN, but despite that, I had it up and running in about ten minutes.



    ($_='kkvvttuubbooppuuiiffssqqffssmmiibbddllffss') =~y~b-v~a-z~s; print