Furthermore, if there's a session in server memory reserved for your use, someone else may be able to hijack the remainder of your session. For the protection of your users and for the overall performance of your site, you should provide a way for them to log out when they're done.
We'll illustrate the problem and look at two ways of handling it. Along the way, we'll work with session variables in ColdFusion. However, similar solutions can be used for other Web middleware.
This code sets the application to expire after ten minutes of inactivity (from any user of the application) and the session to expire after 30 seconds of inactivity (from this user). Whenever a user of the application requests a page, ColdFusion resets both timers. For this demonstration, explicitly avoid using cookies to tie the browser to the session. Using URLs helps show what's going on.
<!--- Simulate Application.cfm ---> <cfapplication name="release" applicationtimeout="#createTimeSpan(0,0,10,0)#" sessionmanagement="yes" sessiontimeout="#createTimeSpan(0,0,0,30)#" setclientcookies="no">
Numerous authors have written about the importance of locking memory variables before writing to them in a multi-threaded environment such as ColdFusion. Set the lock so no other page can write to variables for this session while you're doing it. You can readily do this by naming your lock after the session ID. (If you're using new versions of ColdFusion, you can replace "name=#session.sessionID#" with "scope=session" to accomplish the same thing.)
If you were adding multiple variables to a cflocation URL, you would have to build the URL with a cfset statement first to make your intent clear. However, you can add a single variable to this URL directly. ColdFusion makes it easy to pass the cfid and cftoken in a URL by providing the special variable URLToken. This variable looks like the cfid and cftoken concatenated for use in a URL. Here's an example: "cfid=83&cftoken=12334556".
<!--- Simulate Application.cfm --->
<cfinclude template="appset.cfm">
<!--- Remove cookies to avoid confusion --->
<cfcookie name="cfid" expires="now">
<cfcookie name="cftoken" expires="now">
<!--- Write to the session structure and go to work --->
<cfif isDefined("form.Nickname")>
<cflock name="#session.sessionID#" timeout="30">
<cfset session.ok="1">
<cfset session.username=#form.Nickname#>
</cflock>
<cflocation url="work1.cfm?#session.URLToken#">
</cfif>
<form action="door1.cfm" name="door" method="post">
Enter employee nickname (anything you want):
<input type="text" name="Nickname" value="" size="10" maxlength="8">
<input type="submit" name="submit" value="OK?">
</form>
<!--- Simulate Application.cfm... --->
<cfinclude template="appset.cfm">
<!--- Bounce the user if the session's over --->
<cfif not isDefined("session.ok")>
<cflocation url="door1.cfm">
</cfif>
<!--- Permit logout and work --->
<cfif isDefined("form.logout")>
<cflocation url="exit1.cfm?#session.URLToken#">
</cfif>
You are logged in as <br>
<cfoutput>
#session.username#, session ID #session.cfid#, and token #session.cftoken#<p>
</cfoutput>
Pressing the button simulates work;<br>
staying idle too long logs you out;<br>
clicking "Log Out" also logs you out.
<cfif not isDefined("form.myNum")>
<cfset hold=0>
<cfelse>
<cfset hold=#form.myNum#+1>
</cfif>
<cfform name="work" action="work1.cfm?cfid=#session.cfid#&cftoken=#session.cftoken#" method="post">
<cfinput type="text" name="myNum" value="#hold#">
<input type="submit" name="bang" value="Submit">
<input type="submit" name="logout" value="Log Out">
</cfform>
<!--- Simulate Application.cfm ---> <cfinclude template="appset.cfm"> <!--- Prove that this works ---> <cfset myURLToken=session.URLToken> Leaving session <cfoutput>#session.cfid#</cfoutput> <cfset target="work1.cfm?#myURLToken#"> <p> <cfoutput> Try to work by clicking here...<a href="#target#">#target#</a> </cfoutput> <!--- Make it work ---> <cfset dummy=StructClear(session)>
<cfapplication name="release" applicationtimeout="#createTimeSpan(0,0,10,0)#" sessionmanagement="yes" sessiontimeout="#createTimeSpan(0,0,0,0)#" setclientcookies="no"> <cflocation url="door2.cfm">
If you merely press the back button from exit1.cfm, it appears that you have an active session again, but when you press the Submit button, you'll be bounced to door1.cfm. You can get a taste of the same thing by clicking on the link in exit1.cfm. You'll get dumped to door1.cfm.
Now browse door2.cfm and enter a nickname as you did for door1.cfm. You'll see the same behavior. Try opening a second browser as before, but this time, close the first browser or send it to a different site before sending the second browser to the URL you've copied. It doesn't make any difference. The site didn't know that the first browser had left; so, it left the session active on the server. Now log out. As soon as you do, you'll be bounced to door2.cfm.
[After publication, the phrase "or waits for a timeout" was added to the Recap for clarification.]