Storing page-state in the session is evil / Spammer for a day

This is a cautionary tale on the pitfalls of storing UI state in the session of a webapp.

Very occasionally we have a need to send out a bulk email to a bunch of people. For example: we had several hundred requests expressing genuine interest in The Commentator, one of our April Fools jokes this year, and we sent out a well-humoured email to them explaining it was a joke.

To help manage these mail-outs, we found and installed a nice little cgi webapp. And since I’m currently tracking a handful of people who are participating in the alpha program for FishEye 1.1 (with SVN support), I figured it would save me some time by just using this existing webapp.

Now this webapp is fairly slick: it has a nice-looking UI, plenty of features, and lots of different admin pages you can fiddle with. I went ahead and setup my alpha-program list, and composed an email announcing that the next alpha build was available. At the same time — in a different browser window — I opened up the admin pages for the Commentator list so I could check what settings we had used there. Switching back to the email-composition page, I pressed “submit”.

And suddenly 300 Commentator-hopefuls get an email about the FishEye 1.1 alpha.

And I became a spammer for a day.

And if you have ever written a webapp in-anger, then I’m sure you can guess what went on.

Upon entering the “fisheye-alpha” part of the site, it associated my session (or, more likely in this case, a cookie) with the “fisheye-alpha” list. When it presented the email-compose page, it titled the page “fisheye-alpha compose” because, obviously, that is what I was doing. However, when in another window I started clicking through the “commentator” section, my session became associated with the “commentator” list.

When I then submitted the email form, the browser posted to the webapp the email subject and body. But there was no hidden parameter saying for which mail-list this email was for. Instead, the webapp looked up the mail-list from my session, which was the “commentator” list, and sent them the mail.

The pain! The guilt!

So the moral of this story is simple. If you are using both session-state and request-data when handling a page submit, make sure the scope of the session-state matches the scope of the page.

Imagine some data-collection that is spread over a sequence pages. You can store the data from previous pages in the session: but don’t store them globally in the session. Instead associate them with this instance of the page-sequence. Make up a unique id for this instance on the first page of the sequence, put the page-data in a hashmap (indexed by this id) in the session, and use that id has a hidden parameter on every page.

It’s not that hard. And you might be surprised: make the scope of page-data explicit in your webapp, and it may actually make your code easier to follow.

6 Comments

  1. graham
    Posted July 13, 2005 at 7:39 pm | Permalink

    the problem you’re seeing is actually a problem with the
    cookie implementation in your browser and not a web app prob tho. for example, firefox
    doesn’t see tabs as new windows and will share session state and opening a second
    IE using ctrl-new window sees the second window as part of the same session. however
    using a shortcut to open a second IE will create two different sessions.

  2. Posted July 13, 2005 at 11:10 pm | Permalink

    Graham, why is this a problem with the cookie implementation in the browser? It is quite common that all windows in a single browser “process” share cookies. Safari does this, IE and FireFox do it, etc. And it makes sense that it works that way.

  3. James
    Posted July 14, 2005 at 12:19 am | Permalink

    Yep I had a similar problem on a large web-app. We got around this by associating a master parameter ‘windowId’ to a new scope level. So in effect, you then had page scope, request scope, window scope, session scope, application scope. Forced proper use by by throwing an exception if no request parameter of ‘windowId’ was found. It worked quite neatly.

  4. Posted July 14, 2005 at 9:30 am | Permalink

    I agree. It would be a massive inconvenience if Firefox dropped my cookies whenever opening a new tab. Can you imagine trying to browse Slashdot with that kind of braindead setup? Every time you opened a new tab from a comment link, your session would go away. Which is fantastic because then, every time you wanted to comment back, you’d have to login again. :-)

    Now, window scope… that’s a pretty frigging cool idea. Why isn’t that built into Struts?

  5. graham
    Posted July 15, 2005 at 1:03 am | Permalink

    the browser will decide whether sessions are shared across multiple tabs, even
    windows. it isn’t a limitation of server-side state tho, it is particular to your client.
    I think it’s more important that the user is aware og how their browser will work. i
    had a client that came across a problem because he was using IE and cloning the window
    instead of creating a fresh session in a new window. in reality, the use case of using
    multiple windows is rare amongst clients and the problem he was seeing wasn’t really
    a big issue because people normally wouldn’t use the app the way he was.

    good idea about maintaining another context for page-flow, bit more work, but it would
    have saved me trying to explain the use of sessions in web applications to a non-technical
    client. i also agree with the last comment that it would be great to have support for that
    in the big frameworks like struts and webwork because tabbed browsers are becoming
    more and more popular so the problem will only get worse.

  6. john
    Posted July 21, 2005 at 12:39 am | Permalink

    Graham, no one claims that it’s a limitation of server-side state, but it’s clearly a bug in the way server-side state in concert with client side state (i.e., a cookie) was used in the webapp in question.

    In response to “I think it’s more important that the user is aware og how their browser will work,” users will most definitely NOT be aware of how their browsers will work. That’s why webapps need to be written to work properly (or bomb out and tell the user why) regardless of what weird acts the user performs. Your comment about how it wasn’t really a problem that some user was running into trouble when he Ctrl-N’ed for a new window “because people normally wouldn’t use the app the way he was” is really troubling (or at least it should be troubling to your clients).

Post a Comment

Your email is never shared. Required fields are marked *

*
*