This article is somewhat technical, so if building web applications isn't your thing, you may want to skip it.  I recently finished a project involving a web application for which IE (Internet Explorer) was the target browser.  As the product was going through SQA (software quality assurance -- i.e. testing) news of a rather annoying bug filtered back to me...

Chuck, when the user logs out of the application, if they click IE's back button to get back to the login page, they see a message saying the page has expired and to click refresh to resubmit the form data.  If they do this, they are logged back into the application without having to enter their username or password.

Now you may be wondering if that is really so bad.  If the guy just logged in 10 minutes ago, he obviously knows his username and password.  Does he really need to type it again?  YES.  Consider that the guy who was just logged in, logs out, and leaves work for the day without quitting out of IE.  With this bug in the system, anybody could walk into his office, hit BACK a few times, and get into the system under his username.  Not good.

I was glad to see that the page was expired.  The page is expired deliberately.  If we don't force IE not to cache the pages, it may choose to show the user an old page instead of a current one.  Duh.

And yet, even though we explicitly told the browser not to cache the pages, good old security-minded IE has seen fit to cache the information entered on the forms on all the pages.  Furthermore, it will notify you of this fact and offer to send the information again!  Have I mentioned that when tested with other browsers, this doesn't happen? Further evidence that IE sucks.

I first checked all of IE's settings to see if there was a way to turn off this "feature".  No such luck.  So once again I was put in the position of having to modify a perfectly good web application to overcome a shortcoming of IE.  But how to do it?

I checked the obvious things.  In the HTTP header I sent down a larger variety of directives to prevent caching on the browser, no dice.  IE would not cache the page, but would continue to retain the form information.  I made sure we were removing the user's information from the HttpSession when they logged out.  We were, but it didn't matter since IE was still holding on to the information.

Then I started visiting forums on the web... chances are if you are having a technical problem, somebody out there has already had it and solved it.  A large number of these "solutions forums" have become pay sites (such as Experts Exchange).  This irritates me because the people providing the solutions are not paid by the site, and we already had forums that would facilitate the exchange of questions and solutions for years that didn't cost a thing.  The doubly annoying thing is that the pay sites offer solutions that you can probably find elsewhere for free.  So why pay?

So I began googling and checking both the web and usenet.  It took forever, and along the way I saw the signs of other developers with the exact same problem seeking answers.  I also saw dozens of hokey solutions from so-called "experts" who obviously don't know their trade any better than I.  One guy suggested using JavaScript to access the browser's history of visited pages and delete the login page from the list.  What nonsense.  The capper was the guy who said "I've been building apps like these for years, and that's just a flaw you'll have to live with."

Uh-huh.  Try logging out of PayPal, Yahoo, eBay, or any number of other such sites and then hitting the back button and see what happens.  Guess what.  It works properly, so obviously there is a solution... genius.  Remind me never to hire you!

Eventually I found someone who had hit on the solution, and it was remarkably simple. Ordinarily our web app displays a login page, the user enters the login info, and clicks submit.  This generates an HTTP post containing that information, and if the information authenticates properly on the server, we forward the request on to the application's home page where the user can begin working with it.  Meanwhile IE remembers "in order to see home page, I must send [username] and [password]".

Because IE does this caching by associating the parameters with the resulting page, the solution is to disassociate the parameters from the resulting page.  This is done by redirecting the HTTP post instead of forwarding it.  What's the difference?

A forward happens on the server, the browser doesn't know about it... it submits its post and gets a page back.  It wouldn't matter if we forwarded the HTTP request 20 times--because IE gets a page back from its post it associates the parameters sent with the page returned.

A redirect is different, it happens in the browser.  The way it works is that in response to an HTTP post, the server sends a directive back to the browser that says "go to this other page".  This causes the browser to submit a new request for the other page, and this request has no parameters.  Technically, IE never got a page back when it sent up the username and password, and therefore, it doesn't cache those parameters and associate them with any page.

So now when the server gets the login information, it authenticates the user and either forwards them to a failed login page or redirects them to the application's home page on a successful login.  And it works great.


Since then I found an interesting paper on the web talking about this technique which discusses how one could exploit this "feature" of IE to determine what someone's username and password are.  It also covers the solutions in detail.  Check it out if you want (347K PDF file): Stealing passwords via browser refresh.