Beefy Boxes and Bandwidth Generously Provided by pair Networks
Just another Perl shrine
 
PerlMonks  

CGI Authenticaiton

by packetstormer (Monk)
on Feb 09, 2012 at 16:19 UTC ( #952778=perlquestion: print w/ replies, xml ) Need Help??
packetstormer has asked for the wisdom of the Perl Monks concerning the following question:

Hello Monks.
I have a general question about usign CGI::Session for web page authentication.

I have a very simple web application that authenticates users based on a username and password they supply. The form checks this against the SQL db and if OK redirects them to a page. I would like to stop anyone just bypassing this page(s) by putting the direct URL in the browser.

Looking at CGI::Session I can generate a new CGI session id and pass this along via the URL or hidden forms (I need to assume no cookies will be saved/allowed at the client). I am having trouble with the mechanics of what needs to be done but I am thinking of the following: On every page check for the existence of a cgi->param("sessionid") if none exists redirect to the login page. Is this common practice?
The problem I have then is timing out the users session and/or stopping anyone logging in with the same id. (and I suppose someone adding a sessionID to URL). Is it a good idea to, upon successful login, store the sessionid in the MySQL database and then on everypage check the existing sessionid is equal to the latest one in the db and if not kick them out?

Does anyone have any general thoughts, tutorials on this? I have read the CGI::Session, CGI::Session::Tutorial and CGI::Session::Cookbook and the code isn't really the problem, it's more the method I am struggling with.
Sorry for the long winded, generic question!

Comment on CGI Authenticaiton
Download Code
Re: CGI Authenticaiton
by trwww (Priest) on Feb 09, 2012 at 18:26 UTC

    it's more the method I am struggling with.

    So, you've got these great, well tested libraries of code, but you're having trouble getting them to all work together. Its the same problem we've all faced our first time trying to build a performant, reliable web service. Thankfully, the many before us have helped us solve this problem too.

    Check out CGI::Application. This library provides a framework and conventions so the other libraries you've mentioned have a very basic use case. With this library, you get plugins like CGI::Application::Plugin::Authentication, so you almost don't even have to think about the seemingly simple / deceptively difficult task of authorizing a person to access a resource on the web. Heck, it even gives you a login form so you don't even have to write html. If the defaults suit your tastes, you're not even really writing code, you're just doing configuration.

    In other words, you're looking at the right tools, but there are even more tools out there that make it easy to use these tools. Even if you're unsure how to use these tools right away, keep at it. Its a near certainty that using these tools are going to give you a cleaner, less buggy, more secure implementation.

Re: CGI Authenticaiton
by InfiniteSilence (Curate) on Feb 09, 2012 at 19:08 UTC

    ..timing out the users session...

    Read the perldoc for CGI::Session, not just the first part of it, but the entire thing like the section on the expire() method.

    ...The problem I have then is ... and/or stopping anyone logging in with the same id....

    CGI::Session stores things about the connecting session, hence you will know the IP address of the client that created the session and can, whenever validating that session on every subsequent request, check it again. If it is not the same then deny the request (see remote_addr() in the perldoc).

    Celebrate Intellectual Diversity

Re: CGI Authenticaiton
by Anonymous Monk on Feb 09, 2012 at 20:12 UTC
Re: CGI Authenticaiton
by tangent (Deacon) on Feb 09, 2012 at 20:27 UTC
    Grab the session id and the user's IP address when they first log in. Save that somewhere secure with a timestamp (I use DB_File), then check each subsequent request against what you have stored - the IP to ensure a logged-in user, and the current time against the timestamp to enforce time-outs. You may want to reset the timestamp each time too to avoid annoying your users.
    EDIT: I didn't see InfiniteSilence comment.
      Thanks for the replies.
      I am still a little confused what would happen if someone opened another browser tab(while logged in to the site correctly) and typed in a URL of a page behind the login page. Because I can't store cookies and there wouldn't be any session ID in the URL wouldn't the page look for authencication again? Wouldn't this annoy the user?
      Again, sorry for sounding dumb but I've been looking at this for most of the day and my brain is about to leak out of my eye sockets!
        It may annoy the user, but it's the proper behavior (if this is the way you're doing authentication). If all you have to go on is URLs and maybe hidden fields in POSTs, then "another browser tab" is pretty much the same as "another browser" or "a browser on another computer" for all the state it's communicating up to your server.

        HTTP doesn't really give you that many levers to pull on for tracking state between requests; it's either in the headers or in the body. "Encoded into the URL" counts as "headers", "hidden field in a POST" counts as "body", and about the only other thing you have is "cookie", which is a header. And cookie is the only one that the browser itself knows anything about between requests.

        To me, that boils down to: If you're not able to use cookies, you'll need to figure out a way to spin this "annoyance" as a "feature".

        Just to add to what mcdave said, if you are in an environment where no cookies are allowed then surely your users are aware of this so it's fair enough to tell them that opening a new tab or whatever won't work. I don't really understand why they would do this unless they knew how to construct the correct URL. Maybe they know the IDs of what they are looking for and want to tack that onto the end of the generic URL? If so then if you put the session id parameter before all other parameters in your URLs then the browser's auto-complete function will include it before the bit the user wants to replace - just might work.
Re: CGI Authenticaiton
by tobyink (Abbot) on Feb 09, 2012 at 21:01 UTC

    Have you considered using HTTP auth? If you can't use cookies, it's quite a nice way of doing authentication. You can probably just tell Apache to do it and keep all the authentication stuff out of your Perl scripts. (Hardest part is teaching Apache your database structure so that it can check the passwords.)

    HTTP auth can be implemented in Perl too, but CPAN seems to have a dearth of modules to do it for you. (There are some for Catalyst and Plack, but not classic CGI.)

      HTTP auth can be implemented in Perl too, but CPAN seems to have a dearth of modules to do it for you. (There are some for Catalyst and Plack, but not classic CGI.)

      Right, because classic CGI ( as in mod_cgi, http://tools.ietf.org/html/rfc3875 ) , doesn't provide for external programs to perform authentication (it will strip any Www-authenticate headers) -- its a limitation of CGI

      You can work around it in apache by
      compile Apache with -DSECURITY_HOLE_PASS_AUTHORIZATION option,
      use mod_rewrite to pass the Authorization header to the application with the rewrite rule like following (see Plack::Middleware::Auth::Basic)
      use mod_perl
      use fastcgi configured with "-pass-header HTTP_AUTHORIZATION "

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://952778]
Approved by marto
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others pondering the Monastery: (6)
As of 2014-10-22 05:57 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    For retirement, I am banking on:










    Results (113 votes), past polls