Philip Chalmers

Subscribe to Philip Chalmers: eMailAlertsEmail Alerts
Get Philip Chalmers: homepageHomepage mobileMobile rssRSS facebookFacebook twitterTwitter linkedinLinkedIn


Related Topics: ColdFusion on Ulitzer

CFDJ: Article

Robust CF Session Management

Robust CF Session Management

This is the second part of a two-article series about how to use ColdFusion to solve some common session management problems in Web applications. Part 1 contained:

  • A summary of my recommendations
  • Why you need cookies for session management
  • Detecting and handling timeouts

This part discusses:

  • Back, Forward, Refresh, cloned windows, and multiple Submits
  • Proxy servers
  • Users who enter your site via an inner page
  • Multiple sessions with different browsers
  • Closing a session

Back, Forward, Refresh, Cloned Windows, Multiple Submits
How do you prevent users from getting confused or entering duplicate transactions as a result of using these browser capabilities?

Chromeless Windows Are a Poor Solution
I've seen sites that try to avoid this problem by running the app in a chromeless window opened by a link on the home page. I think this is a poor solution because:

 

  • It makes the whole system dependent on JavaScript and so excludes about 12% of users. Can you afford to turn them away?
  • A user who knows the browser's function keys can use them even in chromeless windows. For example, you can't even detect the use of F5 (Refresh) in Internet Explorer.
  • There are many situations where use of the "Back" and "Forward" buttons is desirable - for example, to return from the product details page to the search results or shopping cart page.
  • The home page becomes a "splash" page, which many visitors will find annoying.
  • Chromeless windows and other pop-ups are disreputable because of the way they've been used to push advertising at users, and many users kill them before they even see the title bar.

    CFLOCK Reads and Writes of Session Variables
    Suppose a user opens two windows containing a page that initiates an update of some session variables, then clicks the "Update" buttons/links on each in quick succession. I'll leave the rest to your imagination.

    The "Back" and "Forward" Buttons
    I wouldn't want to disable these in any way:

     

  • Disabling Back is generally regarded as the ultimate user-hostile act on the Web.
  • The user legitimately may wish to review something from a previous page.
  • So you also have to allow Forward.

    But there's a problem, for example, if a user completes an order, then uses the Back button or browser menu to redisplay a page used in building that order. The system may be showing parts of an order that has already been completed, instead of building a new order.

    So the effect of Back and Forward doesn't matter for some pages but must be carefully controlled in other cases, mainly pages that implement a "transaction" (e.g., the checkout phase of a shopping cart) or that prepare or support a transaction (e.g., update shopping cart and view shopping cart).

    Many advisors suggest using the HTML META tag or CFHEAD tag to disable the browser's cache. But then the browser will often display a screen saying something like:

    Warning - this page is based on form data that has expired - do you wish to resubmit the form?

    and if the user clicks "Yes," you have a potential duplicate Submit as well, which could cause duplication of an order with unpleasant consequences for the user's credit card and your reputation.

    For pages that update data I suggest you create a session-level update counter and increment it whenever you get a request for a display page that can initiate an update to any significant data, whether that data is in a database or in memory (for example, a shopping cart). Include this counter value as a HIDDEN INPUT in every form that can request an update.

    Avoid initiating updates via links, as then you'd have to return the counter to the server as a URL parameter and the user could edit it.

    When the action page receives a request, it should compare the stored and submitted values of the counter. If the submitted value is lower, display a warning about using out-of-date versions of pages, with a link to some suitable point from which the user can resume the dialog.

    If the submitted value is higher, the most likely cause is that there's been a session timeout at some stage. If the stored session variable contains the counter's initial value, the timeout most likely occurred between the time the pages were displayed and when the users submitted the data and you should treat it as a timeout (apologize and link to the startup page). Otherwise the user has probably gone back to a version of the display page created before the timeout and you should display the warning about using out-of-date versions of pages.

    Don't pass the counter in your session management cookie because the browser will always return the latest value even if an update request is sent via an out-of-date page.

    This approach will remove the danger of out-of-date/duplicate updates when the user receives a browser message such as the one mentioned previously.

    The "Refresh" Button
    Refresh on its own is usually harmless. The main danger is when it's used as a response to browser warnings of the same type mentioned above, and we've already seen how to deal with that.

    Cloned Windows
    In 2000 there were reports of an "exploit" that relied on cloned windows that hit several shopping cart systems. A shopping cart was filled, and credit card details were authorized for, for example, $100. The perpetrator then used a previously cloned window to change the details of the goods (which the system thought were authorized by the credit card company) to a higher value. (I got this information from Macromedia's CF forum at http://webforums.macromedia.com/coldfusion/ messageview.cfm?catid=3&threadid=197569) .

    Using an update counter avoids the risk of duplicate or inconsistent updates (or worse, additions) from cloned windows provided that you CFLOCK session variables before updating the page counter.

    Multiple Submits
    Using an update counter avoids the risk of duplicate updates/additions if the user clicks Submit more than once, and without this protection does not rely on JavaScript (about 12% of users disable JavaScript or use non-JavaScript browsers).

    Problems with Proxy Servers
    Proxy servers serve as much as possible from their own caches, so different users get the same versions of pages.

    I've seen reports in Macromedia's support forums (for example, http://webforums.macromedia.com/coldfusion/ arcmessageview.cfm?catid=2&threadid=19588 ) of proxies sharing the same CF session management cookies between users so they're sharing a session! This despite the fact that Netscape's specification for cookies (http://home.netscape.com/newsref/std/cookie_spec.html) says proxies should keep different users' cookies separate and always transmit them in both directions.

    Fortunately, there's a simple solution: append a random number as a URL parameter in all links and in the ACTIONs of all forms, with the same name in all cases. This makes each user's request for the same page look different to the proxy server. CF can generate random integers from 1 to 100,000,000, so the risk that the same page will be requested with the same number by users on the same proxy server within the same week is extremely small.

    Note: In forms the random number must be part of the ACTION, not a HIDDEN INPUT, because this technique requires the random number to be part of the URL as shown in the address/location bar - that's what makes the proxy server think it's a different page.

    It doesn't matter if the user edits the address/location bar. If two users edit it to the same value, the session update counter described above will prevent them from doing anything that compromises your app. Your app will simply ignore the random number parameter.

    Users Who Enter Via an Inner Page
    Of course, users who enter via an inner page are welcome. They're more likely than most visitors to be interested in what your site offers because they've probably got the URL from a bookmark they created after a previous visit, a search engine query, or an e-mail from a friend who knows what they're interested in.

    For these users, required session variables may not exist, and the app's session management cookie doesn't exist unless this is a revisit. The checks on cookies and updating sequence numbers will handle both situations.

    Your "please enable cookies" page must allow for visitors to inner pages. Welcome them, explain why this page has appeared and what could have caused it, ask them nicely to enable per-session cookies, and direct them to your startup page. And links to "about us" and other information-only pages should probably be offered for visitors who've found your site via a search engine or an e-mail - they need reassurance that they've come to the right place.

    Multiple Sessions with Different Browsers
    CF creates a separate session for each different browser on the same client PC (e.g., Internet Explorer and Netscape) because each browser has its own set of cookies and therefore different CFID and CFTOKEN values.

    If you need to prevent or control multiple simultaneous sessions with the same user, you can:

     

  • Require users to log in when the dialog reaches a point where control is needed. You then have the option to reject duplicate log-ins.
  • Maintain an application-level structure keyed on userid and containing a time stamp updated on every page request from the user.
  • Schedule a process to remove entries older than the app's session timeout interval.

    Closing a Session
    You can't force the user to close a session. He or she can simply use the browser to go somewhere else (unless you run your app in a chromeless window) or close the browser window.

    But you may suggest that the user should log out for his or her own security. You could even include JavaScript to create a "please logout" pop-up window if the user leaves your site without logging out. But don't rely on it. Remember, 12% of users run without JavaScript and the rest can close the pop-up.

    If the user does log out:

     

  • Don't use StructClear(Session) in CF 4.5 or later to kill the session; the user may legitimately be using another window to talk to another app on the same site. Instead, clear the critical session variables individually. You can use the app's session management cookie to identify them. Any other app the visitor may also be using should have a separate session management cookie.
  • Delete all name-value pairs from the session management cookie except for "cookiesOn=yes". If you delete this, the app will show the "please enable cookies" page if the user returns. Don't delete the CFID and CFTOKEN cookies because the user may legitimately be using another window to talk to another app on the same site.

    References and Additional Information

  • Macromedia's support forums: Information relevant to the scope of this article, in particular, postings about the hack using multiple browser windows (search this page at http://webforums.macromedia.com/coldfusion/ messageview.cfm?catid=3&threadid=197569 for the word exploit); the history of CF session and client management (Steve Nelson's February 1, 2000, posting in this thread at http://forums.allaire.com/coldfusion/ arcmessageview.cfm?catid=2&threadid=160630 . neatly summarizes the pros and cons of various techniques); several items about the risks of passing CFID and CFTOKEN as URL parameters, including http://webforums.macromedia.com/coldfusion /messageview.cfm?catid=12&threadid=273429 (robbart's posting at 4:30 p.m. on February 25, 2002, points out that search engines can pick up CFID and CFTOKEN from URL parameters and serve them to all their users!); the problems with proxy servers (http://webforums.macromedia.com/coldfusion/ arcmessageview.cfm?catid=2&threadid=19588 ).
  • Netscape's specification for cookies: http://home.netscape.com/newsref/std/cookie_spec.html.
  • Web browser usage and capability stats: www.upsdell.com/browsernews/res_design.htm and www.w3schools.com/browsers/browsers_stats.asp.
  • Funaro, M. (2000). "So You Want to Manage a Session on Load-Balanced Servers?" CFDJ, June (Vol. 2, issue 6).
  • Another method for checking for cookies: www.thenetprofits.co.uk/coldfusion/faq/ (I don't like it because it causes flicker and messes up the Back button if JavaScript is disabled).
  • Webmonkey's tutorial on cookies and CF: http://hotwired.lycos.com/webmonkey/00/29/index3a.html; This explains the basics of using cookies, including some points where the ColdFusion documentation is incomplete or misleading, and gives links to other useful information about cookies.
  • Independent source of information about cookies: www.cookiecentral.com/faq/; section 2 addresses the user's concerns in nontechnical language. I link to it on "please enable cookies" pages to reassure users.
  • Shopping cart: www.freecfm.com/w/Webdeli/Phils_Deli/index.cfm (which I wrote) uses all of these techniques except logging out and controlling multiple sessions by the same user.
  • More Stories By Philip Chalmers

    Philip Chalmers has been working in information technology since the early 1970s. He’s relatively new to ColdFusion, but has specified, designed, and developed systems on platforms ranging from mainframes to PCs in about a dozen languages. His first technical publication appeared in 1979, when he wrote several sections of the Adabas Design Guide.

    Comments (0)

    Share your thoughts on this story.

    Add your comment
    You must be signed in to add a comment. Sign-in | Register

    In accordance with our Comment Policy, we encourage comments that are on topic, relevant and to-the-point. We will remove comments that include profanity, personal attacks, racial slurs, threats of violence, or other inappropriate material that violates our Terms and Conditions, and will block users who make repeated violations. We ask all readers to expect diversity of opinion and to treat one another with dignity and respect.