AspAlliance.com LogoASPAlliance: Articles, reviews, and samples for .NET Developers
URL:
http://aspalliance.com/articleViewer.aspx?aId=694&pId=-1
Preventing Page Review after Logout with Forms Authentication
page
by Richard Dudley
Feedback
Average Rating: This article has not yet been rated.
Views (Total / Last 10 Days): 102047/ 99

Introduction

The inclusion of Forms Authentication in the .NET Framework has made it significantly easier to protect web pages by requiring users to log in to a web application.  One problem with Forms Authentication is browser caching of secured pages.  After a user logs out of an application, they can still review secured pages by using the browser's Back button.  The user is only looking at local copies of pages they viewed while previously logged in, but this can be undesirable in many instances, and present a genuine security risk.

In this article, we will explore a few small coding changes you can make to prevent users from reviewing secured pages after logout.

Preventing Review of Secured Pages

In order to speed up the Internet experience and reduce load on web servers, all browsers keep locally cached copies of the visited pages for a specified amount of time.  Users can set a time limit or space limit in their browsers for the page cache, but few do.  When a browser requests a page from a web server, it checks the timestamp on that page to determine whether the content has changed.  If the timestamps match, the browser renders the local copy; if the timestamps differ, the browser requests the page again.  For the site visitor, it's usually good that the browser has a local copy of any page that does not change frequently, since it's faster to load locally than download everything again.  However, for the webmaster, this can be a problem.  When users log out of a site protected by Forms Authentication, they may still review the local copy of the pages they visited.  This can be a security issue, as well as a nuisance.  The timestamp of pages with dynamic content does not change when the page is loaded, since the timestamp is read from the file system, not set when the page is requested (note that pages with querystring parameters are not usually cached by browsers, as it is evident they are dynamic).  As such, browsers may keep displaying the same old content over and over, instead of requesting fresh content.

Another security problem can arise if proxy servers are in use.  When a browser requests a page through a proxy server, the proxy server compares the timestamp of the requested file to see if it has changed.  If the timestamps match, the proxy server sends its locally cached copy back to the browser.  In the past, if two users requested the same page, they may have received identical copies of the page.  If the page contained dynamic content for one user, another user may have seen something they should not have seen.  Most proxy servers seemed to have remedied this issue by comparing the user who requested the page, but that doesn't mean every ISP or corporation is using a recent version of its proxy server.

Fortunately, web programmers can send three HTTP headers to the browser that specify how long a page should be cached by the browser or proxy server, if at all.  These headers can be set in the HTML code, or set in directly in server-side code.  The three useful headers are Expires, Pragma: no-cache, and Cache-Control.

HTTP Headers Described

Information on using all three headers and how Internet Explorer supports them can be found at
http://support.microsoft.com/kb/q234067/.

Expires

The Expires header is part of both the HTTP 1.0 and 1.1 specifications, and should be supported by every major and minor browser in use.  Per the specification, the Expires header does not prevent local caching of the resource, but rather tells the browser to check for a new version after a particular date.  The Expires header is set to either an absolute date and time to indicate the expiration of the page's content, or a value of -1 to indicate immediate expiration. For your dynamically generated pages, it's suggested to set Expires to a value of -1; for static pages, or ones that change infrequently (daily or longer), it's suggested to set Expires to a specific date value slightly before the next expected update.

Also per the specification, using the browser's Back button should display pages even past their expiration date.  As such, setting the Expires header is not enough, but every page should have an Expires value.

Pragma: no-cache

This header is part of the HTTP 1.0 and 1.1 specifications.  The Pragma: no-cache header is not meant to control browser caching of server responses, but is intended to signal proxy servers to expire the request and properly forward any other similar requests to the web server.

Recent versions of Internet Explorer support the use of Pragma: no-cache to expire responses, but this implementation is not supported by version 5 or earlier, and may not be supported by many other browsers, either.  You may see this header in a number of examples online, but since it is actually part of the request, it is recommended you do not use it in the response stream.

Cache-Control

This header is part of the HTTP 1.1 specification only.  Most browsers and proxy servers in use today should support HTTP 1.1, but the browser option can be configured by the user.  It's probably safe to assume that devices contacting your site support this header, but you cannot count on that to be the case.

You can set Cache-Control to several values:

  • Public: Content can be stored in public shared caches.  Good for your home page and any other publicly available pages.
  • Private: Content can be stored only in private cache.  Proxy servers should not store the content unless they support private caching.  Useful for pages with user interaction; a better method is No-store (see below).
  • No-cache: Content may not be cached.  This is the highest security setting, and should be used for all pages that contain sensitive information.
  • No-store: A better form of Private.  Content may be cached for the length of the session, but not archived.

All applications should set the Cache-Control of their pages.

Setting HTTP Headers in HTML

Any of these three headers can be set in the <head> section of your web page, as shown below:

Listing 1: HTML HTTP Header Tags

<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Expires" content="-1">
<meta http-equiv="CACHE-CONTROL" content="NO-CACHE">

You will need to add these headers to every page, and set their values accordingly.  Internet Explorer versions 4 and 5 do not support the Cache-Control http-equiv tag, so Microsoft recommends setting this value as part of the Response object in server-side code.

Setting HTTP Headers in Server-side Code

In ASP.NET, a class named HttpCachePolicy has been introduced, which gives finer control over expiration and caching of content.  It is recommended that a developer use the HttpCachePolicy class rather than the Response.AddHeader() method to set caching policies.

Listing 2: HttpCachePolicy Properties

Response.Cache.SetExpires(DateTime.Parse("6:00:00PM"))
Response.Cache.SetCacheability(HttpCacheability.Private)

Note that the SetExpires() method only accepts a DateTime value.  Instead of passing -1 as a value, you will need to pass an absolute time (as above), or use the DateTime.Now property to pass in the current time.  According to the HTTP specifications, all absolute times in these headers should be set by Greenwich Mean Time to avoid any strange behavior when crossing time zones.

Additional properties and methods for the HttpCachePolicy class are detailed in the documentation for the 1.1 Framework and Beta 2 Framework.

An easy way to ensure these properties are set on every page is to create an abstract page class that inherits from the intrinsic Page class, and set these properties in the Page_Load or Page_Init handler of the abstract page class.  Then, every page in your application should inherit the abstract page.  This is a much easier way than copying HTTP headers into every ASPX page.

Summary

A simple coding change to a base page class can help ensure users cannot review pages after they log out of a website protected with Forms Authentication.  When used with Session.Abandon and proper expiration of the FormsAuthenticationTicket, you add additional security to your site, and help protect your user’s information.


Product Spotlight
Product Spotlight 

©Copyright 1998-2024 ASPAlliance.com  |  Page Processed at 2024-05-18 11:13:49 AM  AspAlliance Recent Articles RSS Feed
About ASPAlliance | Newsgroups | Advertise | Authors | Email Lists | Feedback | Link To Us | Privacy | Search