thomasfrank.se

Session variables without cookies

January 20, 2008

Security update May 17, 2008
  1. Sanitizer added to prevent eval() of malicious code.
  2. The flag sessvars.$.prefs.includeFunctions now defaults to false.
I never liked the JavaScript implementation of cookies. The storage space is limited (4 x 20 Kb per domain), the only data format that can be used is a string and the syntax for setting and getting cookies is unnecessarily complicated.
On top of that they get added to the browser request header - and since a lot of corporate firewalls only accept a rather limited request header length they might prevent your pages from loading at all. (I've seen it happen - it's ugly.)
So I've made a small script that let you use JavaScript session variables without using cookies. It will let you store 2 MB of data, with much less hassle than a cookie based solution.
Embed sessvars.js (6 Kb) in the head section of every web page where you want to use session variables, before any other scripts that try to set/get them:
<head>
<script type="text/javascript" src="sessionvars.js"></script>
...
</head>

How to use

You now have access to a new object called sessvars. It works just like any normal JavaScript object --you can add new properties to it and change the values of already assigned properties. The only difference is that sessvars will survive between different pages in your site. So if you script does something like:
on one web page you will be able to access the object sessvars.myObj on all the other pages the user navigates to during the same session.
Try it out on these test pages.

Methods

The only property of sessvars you shouldn't tamper with is $, because it contains a number of helpful methods:

sessvars.$.clearMem()

Clears the memory of sessvars.

sessvars.$.usedMem()

Returns how much memory sessvars uses in Kb.

sessvars.$.usedMemPercent()

Returns how much memory sessvars uses in % of the total memory allowed.

sessvars.$.debug()

Shows a debug window at the top of the page (like in the example above).

sessvars.$.flush()

Explicitly saves the current state of sessvars so that all data survives when you go to the next page. This should rarely be needed, as it is normally done automatically when the unload event fires.

Preferences/flags

There are also some different flags you can set that governs how sessvars behaves:

sessvars.$.prefs.memlimit

[2000 {default}]
How many Kb of data you can store in sessvars. Defaults to 2000 Kb, because Opera 9.25 seems to have a limit just above that. IE7.0, Firefox 1.5/2.0 and Safari 3.0 all have higher limits -- 10 MB is no problem in those browsers.

sessvars.$.prefs.autoFlush

[true {default} /false]
Determines whether sessvars should flush/save automatically (see methods).

sessvars.$.prefs.crossDomain

[true/false {default}]
If this flag is set to true the content of sessvars can be read across different domains (if both sites use sessvars.js).

sessvars.$.prefs.includeFunctions

[true/false {default}]
Determines whether sessvars remembers functions assigned to it across page loads.

sessvars.$.prefs.includeProtos

[true/false {default}]
If this flag is set to true sessvars remembers properties assigned to the prototype of different data/object types across page loads. Rarely needed.

Behind the scenes -- how is the data stored?

The principles behind sessvars.js is really rather simple:
I make use of the fact that you can set the window.name property through JavaScript -- this is a property originally intended for naming windows and frames so that the you might address them by name in your scripts. In order not to interfere with this use in framesets (if anyone still uses them) my script only sets the top.name property.
The beauty of window.name is that the value survives between page loads (and even between domains) and that it can hold a very long name. The downside is that it can only hold a string value. To get around this I use a JSON stringifier to serialize/de-serialize object data, thus being able to pack/unpack it nicely.
On top of the I add an event listener to the window unload event which eliminates the need for a manual save/flush action to be peformed every time you change something in the sessvar object.

Security considerations

There is a cross domain flag in sessvars, but although it defaults to false, this just sees to that you don't get any other sites window.name garbage inside your sessvars by mistake. The actual data you set will be available for other scripts on other domains to look at -- and also to anyone able to type javascript:alert(window.name) in the browser's address bar.
Therefore: Please, do not store sensitive information in sessvars, like passwords, visa card numbers etc.
But in some aspects sessvars.js is safer than cookies: The content of window.name does not get sent to the server in the header request -- the content of a JavaScript cookie does, making it easier to sniff.
[comments]