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

I'm trying to decide on a session management technique. There are so many PMs out there that I don't know what would be best to use.
Once users are logged in, they should be able to browse the site without re-entering their username/password (unless inactive for a period of time).
I know that normally you wouldn't want to pass the username/password between the client and server as plain text, but this site will be running SSL. Does this mean I shouldn't worry about passing the username/password between the browser and server?
I don't really need to track anything other than the username/password. This isn't a shopping cart or anything like that. It is however important that it is very secure. Any suggestions would be greatly appreciated.
Thanks,
Jeremy

If you can use mod_perl, then try with
Apache::AuthCookie; module's documentation
is very clear about its benefits, it says:

The client doesn't *have* to pass the user credentials
on every subsequent access. If you're using passwords,
this means that the password can be sent on the first
request only, and subsequent requests don't need to
send this (potentially sensitive) information. This
is known as "ticket-based" authentication.

When you determine that the client should stop using
the credentials/session key, the server can tell the
client to delete the cookie. Letting users "log out"
is a notoriously impossible-to-solve problem of
AuthBasic.

AuthBasic dialog boxes are ugly. You can design your
own HTML login forms when you use AuthCookie.

I found it quite interesting :) But this solves only
half of your problem: you need also session management,
right? Apache::Session could be an answer, but
you may need to put some glue between these two modules.

When you determine that the client should stop using the credentials/session key, the server can tell the client to delete the cookie. Letting users "log out" is a notoriously impossible-to-solve problem of AuthBasic.

Isn't the usual reason a server decides to 'log a client off' because of session timout after 20 mins or so? This normally occurs when they have simply moved on to another site or disconnected without informing the server they are doing so... in which case, there is not client to send the instruction to delete the cookie.

Also, how does the server 'tell the client'? I know there is such a thing as 'server push', but I didn't think this had ever made much of an impact. Besides...

The other way the timeout can occur is if the user is reading something long. If I was doing this and the server suddenly decided to 'send' me a 'your logged off' page, I don't think I would use that site again in a hurry.

I think anything that relies on cookies is gonna limit your audience severely, and more so as new users become aware of the potential for misuse of cookies. The latest browsers that allow cookie control on a site-by-site basis mitigate this problem somewhat, but that requires users knowledgable to distinguish between sites they can trust and those they cannot. Unfortunately, things like the Trust-E symbol aren't worth the band-width that it takes to transmit them, as very little verification is done. ANd what verification is done, is done against the site "privacy policy", which invariably can be paraphrased as:

<rant>

{20k omitted}...of course, we won't use your private details for anything bad, but if we can find a way of screwing some commercial gain by using them to promote some aspect our, or our partners (Read:anyone who will pay us) businesses to you, we will! And by having said this here, hidden on another page linked from every page, in totally oblique, long-winded, legal terminology and frustratingly tiny print, we've effectively covered our arses should you ever discover what we are doing.

Your worries about compatibility can be solved using
different solutions to the same problem. If you don't
want cookies, then just use something like
Apache::SessionManager, which can handle sessions
inside URIs.

Of course, this doesn't resolve privacy issues, as you
can imagine, because it is still possible to track a user
even without cookies. On the other hand, it would be quite
impossible to put something in a basket on Amazon or build
something like PMonks, without something holding a state.
So there is no escape, except honesty.

BTW, it is possible to expire AuthBasic accounts.
Using cookies, just send an empty cookie (delete it) and the
user will not enter your site without re-authentication. Under
AuthBasic, just disable an account inside your htpasswd file.
But you will need some more glue :-))

Also, how does the server 'tell the client'? I know there is such a thing as 'server push', but I didn't think this had ever made much of an impact.

The server "tells" the client (to delete the session cookie) in response to a request from the client. In the timeout case, the server can also refuse to handle the request.

Push isn't needed. If a web application really, really needs to know on a minute-by-minute basis whether the server thinks the client is logged in, use a hidden frame that refreshes on a periodic basis, and expire the session cookie on refresh. You can also include a javascript snippet to communicate "I've been logged out" to some non-hidden frame element.

Hi glickjd,
The most secure system I have used for this type of scenario is a piece of OS software by the name of Interchange. It is touted as predominately an eCommerce solution but is actually a very good 'content management' system with eComm facilities built in. Supports either flat file or SQL Db management for the backend and utilises session management by creating a flat file filehandle for storing any arbitrary data that is desired. It may be a little OTT for your application but I would advise a quick look anyway as you may find some of the features to your liking. My main reason for suggesting this S/W is that is incredibly secure and written in Perl... YMMV.

There's actually a third way that nobody has discussed yet, and in fact, it's the only way to do sessions properly, and in a secure fashion without depositing any insecure information that can be misused on the user's computer: Hidden Fields.

Before you jump on and flame me, here's why: Hidden Fields do not leave "droppings" on the user's computer in any location (well ok, in their browser cache, but it expires once the page is reached anyway, if built properly). It also does not leave any bits in the URI for someone parsing their referer logs to go back into. I've actually managed to parse my own weblogs, caught an ugly referer, followed it back, and was into someone else's online mailbox. Not cool.

Putting the session_id into the URI may fail in a lot of situations, such as with users behind a caching proxy. In many countries this mode of operation is essential due to saturation of international network connections.

In my case, my users are very specific about what they will and will not allow on their systems.

No cookies, at all, of any type

No hashing or unique session identifiers in the URI

Nothing left on their system when they leave my site

It tends to be more of a pain than the other methods, but I gain more happy users (most of them are in Europe, which tends to take a very suspiscious tack with US websites and methods lately), and I get the benefit of their input on things like reporting bugs in the bugtracker, using the cvs, and so on.

A couple of basic rules apply to any session management you build:

No client information at all can be sent in the session. You'd be surprised at how many sites that do session management put client information into the session or cookies themselves, like IP or hostname. Don't.

Always hash the information you pass to the client, and make sure to use good entropy when you do. There are a few sites onthe web that can check entropy of cookies for you for strength. Use them to test your cookies, sessions, and code before you go live with your site.

Never assume the capabilities of the client, including their browser, proxy, cache, or connection. Each of these is subject to fail or perform in unpredictable ways at any time. Do not guess.

Consider what you're passing in the session, and why, then consider it again. Is it really needed? Can you pass something else in a different way, and achieve the same result?

Now the catch, Hidden Fields have their own set of flaws:

Hidden form fields aren't really hidden. Any information stored in a hidden form field can be seen by anyone who views the source code of the web page. If you've stored runtime options to your CGI script, private user data, or anything else in hidden form fields that you don't want seen (or modified) by users, then you shouldn't use hidden form fields, or take some steps to obscure that information

Hidden form fields make it easier for users to break your state preservation mechanism. If you are using hidden fields to track state between pages (such as an online shopping cart), you are likely passing a session_id around between pages. If someone malscious were to get a hold of that session_id, they could jump in and hijack the session.

Fortunately for us as designers, these types of attacks on a session management system are quite preventable, as long as the system is designed with security in mind. here's a few precautions you can take to protect yourself from these sorts of attacks:

Never use user names or passwords, or other relevant data as the session_id. This makes it easier for malicious users to hijack your sessions. Also, generating a new session_id for each session allows you to address each session individually.

Always make sure that your sessions time out after a specified period of inactivity. You want to give users enough time to process the content of each page before their session times out, but you don't want sessions to linger long after the user finishes with the site.

Provide users with a "Sign Off" button, which allows them to terminate their session before they leave the site. This also provides a measure of protection that can prevent sessions from lingering after they're out of use.

Map the session_id to another identifier, like the user's IP address (remember not to store it "in the clear" as mentioned before). This prevents users on one computer from hijacking the session from another, although it doesn't make it impossible.

The W3C has a good explanation of similar issues on session security found here. Read it if you are considering building a site that incorporates sessions or tracking user interaction within your site or realm.

Putting the session_id into the URI may fail in a lot of situations, such as with users behind a caching proxy.

By "fail" do you mean that the pages will not be cacheable by the proxy? In that case, hidden form fields have exactly the same problem, since the content of the page has to be different for every user. Proxy servers don't cache POST requests and GET requests coming from a form submission look identical to URIs with query args on the end. Hidden fields also have the problem of making every single link a form submission, which is a real pain and means replacing text links with images and buttons.

Also, your use of the remote IP as part of your session ID does not prevent people from hijacking a session, it just makes it harder to guess a valid one, and it is possible to create duplicate IDs when using this in a cluster. It would be safer to use mod_unique_id for generating the ID and then use a MAC to verify it when it gets sent back, as described here.

Thanks for the feedback guys. I was since my posting, I've done a little thinking and have an idea how to do this. Here's my idea, please let me know what you think.

Each user will have a record in a database. When the user initially logs in, it will verify that they entered the correct username and password by comparing to the values in the database.

After it verifies the username and password are correct, it will assign a random string of text (session ID) and it will write this session ID along with the current time, to the record in the database. It will also write this session ID along with the username to a cookie.

Now when the user loads another page, it will pull the session ID and username from the cookie. After it finds the matching session ID and username in the database, it will check the time in the database (time session ID was assigned). If that time is over a certain limit, it will timeout and display the login screen...otherwise it will allow the user to continue and will assign a new session ID and time to the databse and the new session ID and username to the cookie.

I figure since all these pages are encrypted with SSL, it's not a having the session ID intercepted is not a concern. Plus, the session ID is changed each time, so even if someone got a hold of it, it will have probably changed or timed out by the time they can use it.

Any comments or suggestions? Do you see any problems here? Do you think this would hold up and perform well with a large amount of users?