http://www.perlmonks.org?node_id=194780

the_Don has asked for the wisdom of the Perl Monks concerning the following question: (cgi programming)

I posted this under HTTP/FTP clients because I was looking for a different solution. However, there were not many responses (zero, to be specific). So I have reposted it here where it makes more sense.

I am thinking about creating a website that will have multiple users. I need to be able to log them in so the page content is appropiate. There will be a DB; which one is not yet determined... so long as its free.

In the past, I used PHP with MySQL and every page required a query to the DB for the user name and PW to verify the user... Is there a better way to securely verify the identity of the person logged in without making a call to the DB (username/password) for every page?

There is a lot of information out there regarding this, so lengthy answers are probably a waste of your time, unless you dont mind typing. I would appreciate it if those who have experience that allows them to weed out the crap from the cream, point me to the cream :-)

I thank you now for your time and expertise.

Originally posted as a Categorized Question.

Replies are listed 'Best First'.
Re: How to remember who is logged in...
by JaWi (Hermit) on Sep 03, 2002 at 15:28 UTC
    Hi!

    Indeed there are many ways you can solve this problem. One of the approaches I used for a site was the following.

    • Let the user login through a nice form.
    • Check in the database wheter the given username/password combo is correct.
    • If correct, I created a session which holds the flag denoting the user is logged in
    • Send a cookie with the username.

    Each time the user returns to your site, you check wheter he still has the cookie. If so, you're (fairly) certain the user has come back and continues browsing your site.

    Logging out can be done by resetting/deleting the cookie (after the user has pressed a `logout' link or automatically after a preset time).

    Of course this is a very simple approach of remembering users (and might not be sufficient in some cases), but I hope it gives you an idea!

    Greets,

    -- JaWi

Re: How to remember who is logged in...
by Chady (Priest) on Sep 03, 2002 at 18:02 UTC
    a note to JaWi,
    you might want to send the session ID in the cookie and not the username, and keep the username in the db along wih its relative ID or else you'll be vulnerable to cross site attacks.
    (someone logs in, and another guy sets his cookie to this guy's username...)
Re: How to remember who is logged in...
by Hero Zzyzzx (Curate) on Sep 03, 2002 at 23:48 UTC

    Check out CGI::Session by Sherzod Ruzmetov (sp?) (not the one by Jeff Younker, which I don't know anything about), it makes session management easy, and includes storage for DB_file, MySQL, and flat files. It's very nice, and a definite time saver.

Re: How to remember who is logged in...
by pope (Friar) on Sep 05, 2002 at 04:19 UTC
    Here is the code snippet I usually use, I hope it's not hard for you with PHP background to follow:
    my %who = (); # tied hash my %c = fetch CGI::Cookie; # received session cookie my $sid; # session id my $sc; # session cookie to sent if (%c) { # check existence of cookie # print STDERR Dumper %c; if (exists $c{sid}) { # check existence of session id in cookie $sid = $c{sid}->value; # untaint: ($sid) = $sid =~ /(.+)/; } } if ($sid) { # attempt to retrieve user information from session id eval { tie %who, 'Apache::Session::File', $sid, { Directory => $session_dir, LockDirectory => $session_lock_dir, }; }; if ($@) { # can't revive session id, probably already garbage-collected $sc = create_cookie($sid, "expires"); undef $sid; } } # if login is submitted, tie a session and retrieve $sid if (param('login')) { my $uname = param('uname'); my $upass = param('upass'); my ($uinfo, $mesg) = $db->auth_user($uname, $upass); unless ($uinfo) { # failed authentication. do smth and exit. } else { # generate session and send cookie in header eval { tie %who, 'Apache::Session::File', undef, { Directory => $session_dir, LockDirectory => $session_lock_dir, }; }; if ($@) { die "Can't create session: $@"; } $sid = $who{_session_id}; # store anything valuable $who{name} = $uinfo->{name}; $who{gname} = $uinfo->{gname}; } } if (exists $who{name}) { # if (%who) doesn't work here! why? # a user is currently logged in. # do smth he/she is allowed to do } else { # user is not logged in }
    I don't know the fundamental difference between Apache::Session and CGI::Session. Both looks quite similar, with an important difference that CGI::Session uses Data::Dumper which is a standard module for its data serialization. Apache::Session uses Storable which requires separate installation, and a C compiler (it has XS code).

    Yesterday I had a bad time with Apache::Session which fails to store data and ended with warnings in error log such as this:

     (in cleanup) Can't call method "update" on an undefined value at
    /usr/local/lib/perl5/site_perl/5.6.1/Apache/Session.pm line 508 during
    global destruction.
    
     (in cleanup) Can't call method "close" on an undefined value at
    /usr/local/lib/perl5/site_perl/5.6.1/Apache/Session/File.pm line 41
    during global destruction.
    
    The strange thing is this happens only with an application I'm currently working on, I have several other applications running Apache::Session without problem. The logic for sessions storing and retrieval is the same, and that is the same code snippet as above. After several hours wasted to locate the problem, I tried CGI::Session. The interface is quite similar to Apache::Session, so changes is quite minimal: s/Apache/CGI/. And.. the problem disappeared (!)

    I just couldn't believe that this is a problem with Apache::Session which is already out there for a couple of years. But now I'm sure that CGI::Session is a very good alternative to Apache::Session.

      If you use any session manager that uses Data::Dumper like CGI::Session does, then remember that Data::Dumper is not writing out simple data and then reading it back in. Data::Dumper writes out Perl code that is evaluated when you de-serialize your data. That means that if anybody has an opportunity to mess with your data files while they are sitting on the file system then you have a huge potential security risk.

      If you use Data::Dumper, be absolutely certain that nobody has write access to the data files that should not. I really don't like to use Data::Dumper for anything in CGI, partly for that reason and partly because it's just slow. You might want to look at using FreezeThaw. It's pure Perl so it doesn't require anything special, but it writes and reads data blocks instead of Perl code.

        This can be avoided using the Safe module. Build the compartment to evaluate the Perl-code configuration using
        $compartment = new Safe; $compartment->permit_only(qw(:base_core :base_mem)); # very restrictiv +e $result = $compartment->reval($unsafe_code);
        and the evaluated code will not be able to do anything than build data structures. (See perldoc Opcode for a list of tags.)

        Makeshifts last the longest.

Re: How to remember who is logged in...
by schweini (Friar) on Oct 14, 2002 at 00:57 UTC
    here's what i usually do:
    after authentication, i send the user a cookie with the sessionid, and log that in my DB. every time the user clicks somewhere, i look up that sessionid in my db, check whether that session "timed out". if the session's still alive, i set my "lastaction" column to time().
    oh, yea - i also log the $ENV{'REMOTE_ADDRESS'}, just in case somebody steals the cookie (i know - IPs can be faked, but it ain't THAT easy).
    sometimes, i Storable::freeze and Storable::thaw some session-data into my DB, too (can come in quite handy).
    i know this is kinda re-inventing the wheel, but it's a small wheel, and i personally like knowing everything about my session-managment, so that i can do whatever i please with it anytime.
    speaking of security: what's the most secure way to handle sessions? how do banks do it? is there another way?
Re: How to remember who is logged in...
by Anonymous Monk on Oct 13, 2003 at 22:11 UTC

    I don't have much to add, except CGI::Session can use both Data::Dumper and Storable as well as FreezeThaw to freeze and thaw data.

    By default it uses Data::Dumper, so that it doesn't require any seperate installations to get it working. However, the only disadvantage of using Data::Dumper over the other two data serializers is it doesn't do good job in thawing stored objects.

    Storing objects in session data is not something one normally does, so Data::Dumper is usually just what you need.

Re: How to remember who is logged in...
by true (Pilgrim) on Oct 14, 2002 at 10:48 UTC
    I've had good luck with an ip based tracking system which records a cookie to the user's machine. The cookie stores the ip address of the visitor the last time they visited the site. This works well b/c when a visitor returns to the site, his last cookie can be used as a lookup for his/her preferences file.

    The login is a list of allowed ip addresses. If the visitor's ip file says they are logged in the visitor is logged in.

    As i understand ip spoofing, and please correct me if i'm wrong. ip addresses can be rerouted to look like it came from another location, but the actual ip address itself can NOT be spoofed. One ip for every net connection, so far as this is the case, it doesn't matter what the actual numbers are, just as long as they are unique. Therefore ip redirect/masking services are not a concern.

    if i'm wrong about the ip spoof i would love to be corrected. I've been curious about this for a while.
A reply falls below the community's threshold of quality. You may see it by logging in.