Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Asp Net 2.0 Security Membership And Role Management

.pdf
Скачиваний:
55
Добавлен:
17.08.2013
Размер:
12.33 Mб
Скачать

Chapter 5

In the case that the browser supports cookies, the ticket is simply packaged into a cookie and added to the Response.Cookies collection. However, if the auto-detect process determined that cookies are not supported then both of these methods will package the hex string representation of the forms authentication ticket into the URL. The general form of the cookieless ticket in the URL is F(ticket value here).

The sample address bar below shows the results of a successful login on a site that uses auto-detection. Note how both the “X” and the “F” identifiers exist in the URL — one indicating the cookies are not supported, and the other containing the cookieless ticket. To make it bit easier to see everything the “X” and “F” identifiers are bolded.

http://demotest/Chapter5/cookieless/(X(1)F(Tcno7kjNtrYWYXyUPpG1x3Cenve7uFN6qdXVkkSQ BiyHig-VFOYxM55reX7q3waJL3aDDv-kz_X_YAlkQfjcIA2))/default.aspx

Subsequent Authenticated Access

After logging in, there really aren’t additional phases to the initial auto-detection process. Auto-detection has occurred, and the results of the process are now indelibly stamped into the URL and maintained on each and every request. ASP.NET automatically takes care of hoisting the embedded URL values into the custom header using aspnet_filter.dll, and various downstream components like forms authentication contain the necessary logic to check for cookieless artifacts (such as the X identifier and the F ticket in the URL).

How to Simulate This in Internet Explorer

It can be a bit of a pain to actually get auto-detection to slip into cookieless mode using a browser like Internet Explorer. By default, IE of course supports cookies, so setting “AutoDetect” in config will only show you the parts of the first two phases of auto-detection before defaulting to using cookies. However, with a bit of rooting around inside of IE you can force it to reject or prompt for cookies — at which point you have a way to simulate a cookieless browser.

First, go to Tools ‡ Internet Options and click on the Privacy tab. Clicking the Advanced button pops up another dialog box as shown in Figure 5-3. In my case, I set the options for cookies to Prompt, though if you don’t want the hassle of always rejecting cookies you can just set the options to Block.

Figure 5-3

212

Forms Authentication

Now you can navigate to your website to test it in cookieless mode. However, you must request your pages using the machine name of your web server. Looking at the last few URL samples, notice how the URL starts with a machine name (http://demotest) as opposed to the usual http://localhost. If you use http://localhost the cookie options you set on the Privacy tab are ignored.

UseDeviceProfile

Device profiles are another mechanism for determining browser cookie support. Although an exhaustive description of devices profiles is outside the scope of this book (the current browser profiles include reams of information that mobile developers care about but that aren’t terribly relevant to security or forms authentication), it is still important to understand where the profiles are located and, in general, how profile information affects detection of cookie support.

UseDeviceProfile is the default setting of the cookieless attribute in forms authentication. This means that whenever the forms authentication feature needs to determine whether a browser supports cookies, it looks only at the values of Request.Browser.Cookies and

Request.Browser.SupportsRedirectWithCookie. If both those values return true, then forms authentication issues tickets in a cookie — otherwise, it uses the F() identifier in the URL.

The information in the Browser property, which is an instance of System.Web.HttpBrowserCapabilities, comes from browser information files located at:

%windir%\Microsoft.NET\Framework\v2.0.50727\CONFIG\Browsers

Note that the actual version number for the framework may be slightly different at release. This directory contains two dozen different files, all ending in .browser. ASP.NET internally parses the information in the .browser files, and based on the regula- expression-based matching rules defined in these files, determines which .browser file applies based on the user agent string for a specific request.

For example, when running Internet Explorer on my machine, the user agent string that IE sends down to the web server looks like:

Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; .NET CLR 1.1.4322; .NET CLR 2.0.50309)

If you look in the Browsers subdirectory, and open up the file ie.browser, you will see that the browser capabilities files define a regular expression matching rule like the following:

<userAgent match=”^Mozilla[^(]*\([C|c]ompatible;\s*MSIE (?’version’(?’major’\d+)(?’minor’\.\d+)(?’letters’\w*))(?’extra’[^)]*)” />

Just from glancing at the regular expression syntax you can see how a match occurs, anchored around the Mozilla and MSIE identifiers in the user agent string. When ASP.NET evaluates this regular expression at runtime, and finds a match, it consults the other information in the ie.browser file and uses it for the information returned in Request.Browser. For example, if you were to query Request

.Browser.TagWriter, you would get back the string System.Web.UI.HtmlTextWriter. I use the

TagWriter property as an example because without the browser capabilities files, there is no way ASP.NET could possibly come up with a .NET Framework class name just from the information sent in the HTTP request headers.

213

Chapter 5

If you open up ie.browser in Notepad, and scroll down a bit to the <capabilities> section, you see a number of individual <capability> elements. The one of interest to forms authentication is:

<capability name=”cookies”

value=”true” />

Because this capability is set to true, in the default out-of-box ASP.NET configuration, forms authentication will always assume that IE browsers support cookies. You can verify this behavior by doing the following:

1.Change the value in the capability to false and save the .browser file.

2.Recompile the browser capabilities assembly. You can do this by running the command aspnet _regbrowsers -I from the framework install directory. This has the effect of reparsing all of the .browser files and then encapsulating their settings inside of a GAC’d assembly. Note that if you fail to do this the changes made in step 1 will not have any effect.

3.Within Internet Explorer, make sure you carried out the steps described earlier in the “How To Simulate This” section.

4.Set the cookieless attribute in web.config to UseDeviceProfile.

Now if you request an authenticated page in the browser, forms authentication will use the device profile information, and thus automatically assume that the browser doesn’t support cookies. No autodetection mechanism is necessary. When you log in, forms authentication will place the forms authentication ticket in the URL inside of the F() characters. Unlike the auto-detect case though, there will be no X(1) in the URL, because the device profile deterministically indicates that the browser does not support cookies.

Although editing the IE device profile is a bit contrived, device profiles provide a fixed way for determining cookie support in a browser. The downside of UseDeviceProfile is that it can’t accommodate new browser types that have totally new user agent strings — for example, if I created a new browser that sent back a user agent string My New Browser, this isn’t going to match any of the predefined regular expressions defined in the various browser capabilities files. In this case, ASP.NET will simply fallback to the settings in the Default.browser file, which may or may not contain correct information. As a side note, Default.browser indicates that cookies are supported, so any user agent that is not recognized by the myriad .browser files shipping in ASP.NET 2.0, will automatically be considered to support cookies.

Another limitation of UseDeviceProfile is that device profiles don’t honor the intent of the browser user. A website user may intentionally disable cookies in any of the major desktop browsers. However, with UseDeviceProfile the user can never log in to your site because ASP.NET will always assume that cookies are supported. Each time the user attempts to log in, ASP.NET will send the forms authentication cookie back, and of course the browser will promptly reject it. Then when the browser redirects to a secured page, the lack of the cookie will simply dump the browser right back to the login page.

Although you definitely have the option of telling website customers up front that cookies are required to login, you also have the option of switching to AutoDetect instead. If you have a sizable percentage of customers that do not want to use cookies (or perhaps you have regulations that mandate support for cookieless clients), then the AutoDetect option may be a better choice than UseDeviceProfile. However, make sure to read the topic about security implications of cookieless tickets in a little bit so that you understand the ramifications of placing the authentication ticket in the URL.

214

Forms Authentication

Replay Attacks with Cookieless Tickets

Although both cookie-based and cookieless forms authentication tickets are susceptible to replay attacks, the ease with which a cookieless ticket can be disseminated makes it especially vulnerable. As an example of how easy it is to reuse a cookieless ticket, try the following sequence of steps on an ASP.NET site that is configured to run in cookieless mode.

1.Log in with valid credentials and confirm that the cookieless ticket shows up in the address bar of the browser.

2.Copy and paste the contents of the address bar into some other location like notepad.

3.Shut down the browser.

At this point, you have your very own forms authentication ticket sitting around and available for replay for as long as the expiration date inside of the authentication ticket remains valid. If you paste the URL back into a new instance of your browser, you will successfully navigate to the page indicated in the URL. If you know the names of other pages in the site, you can edit the pasted URL — the important and interesting piece of the URL is the forms authentication ticket that is embedded within it.

Probably the most likely potential for security mischief with cookieless tickets in this case is not a malicious user or hacker. Rather, website users that don’t understand the ramifications of having the forms authentication ticket in the URL are the most likely candidates for accidentally inflicting a replay attack on themselves. Imagine the following scenario:

1.A website customer visits an e-commerce site that issues cookieless authentication tickets. The customer adds some items to a shopping cart and then logs in to start the checkout process.

2.At some part into the checkout process, the customer has a question — maybe about price. So, the customer copies the URL into an email message. Or for a nontechnical user, just selects FileSend Link by Email. Now the customer has a URL with a valid forms authentication ticket sitting in an email message.

3.When the recipient receives the message, the recipient clicks the URL in the email (or the URL may be packaged as a clickable URL attachment), and surprise! The recipient just “logged in” to the e-commerce site as the original user.

Given the default of sliding expirations in ASP.NET 2.0 forms authentication, after a cookieless ticket makes it outside of the boundaries of the browser session where the ticket was originally issued, it can be reused as long someone uses the ticket before the expiration period is exhausted.

This scenario gives rise to a very specific piece of security guidance when using cookieless forms authentication:

Never use sliding expirations when there is any chance of issuing cookieless tickets!

I understand many of the arguments that can be made against this advice — chiefly that authentication tickets with absolute timeouts lead to a poor customer experience. However, I guarantee that if website customers accidentally email out their forms authentication ticket, their ire over exposing their personal account will vastly exceed the pain of customers having to periodically log back in again. And don’t forget that after someone accidentally leaks his or her forms authentication ticket in an email, every server and network route along the delivery path has the potential of sniffing and stealing a perfectly valid cookieless ticket.

215

Chapter 5

Although the scenario I described earlier involves a customer sending a link to a secured page in a site, the reality is that after the forms authentication ticket is embedded on the URL, it remains there for the duration of the browser session. This means that if a customer logs in to start a checkout process but then clicks back to a publicly available page (maybe the customer clicks back out to an items detail page in a web catalog), the forms authentication ticket is still in the URL. I will grant you that sending an email link from deep inside a checkout process is probably unlikely — however, accidentally emailing the forms authentication credentials from a catalog page in an e-commerce site strikes me as a very likely occurrence.

This leads to a few additional pieces of advice about cookieless tickets:

1.Do not use cookieless tickets for any type of high-security site. For example, do not use cookieless tickets for an online banking or investment site. The risk of someone accidentally compromising themselves far outweighs the convenience factor.

2.If you set the requireSSL attribute on your site to true, ask yourself why you are allowing cookieless tickets. The requireSSL attribute doesn’t protect cookieless tickets — it only works for cookie-based tickets. Although it is reasonable to set requireSSL to true on sites that support mixed clients (the theory being that at least the browsers that do support cookies will have a more secure experience), be aware that for cookieless users the forms authentication ticket can be issued and received over non-SSL connections.

3.Try to set the timeout attribute on sites that support cookieless clients to as small a value as possible. I would not recommend setting a timeout greater than 60 minutes — although it is understandable if you can’t get much shorter than 45 minutes given the usage trends on e-com- merce sites.

4.If you think your cookieless customer base will accept it, you should reauthenticate the customers prior to carrying out any sensitive transaction. This would mean requiring cookieless customers to reenter their username and password when they attempted to finalize a purchase or when they attempt to retrieve or update credit card information.

The Cookieless Ticket and Other URLs in Pages

Throughout the discussion, it has been stated that ASP.NET automatically handles maintaining the cookieless ticket in the URL. Although this is true for server-side code, the placement of the cookieless ticket in the URL also depends on browser behavior with relative URLs. If you look carefully at the sample URLs shown earlier, you can see that the URL consists of a few pieces. For a page like default.aspx, the browser considers the current path to the application to be:

http://demotest/Chapter5/cookieless/(X(1)F(BS3d6LKEP5D74Rw6F2Lq1n-

O9Ot6jzkZQpYhhHDW9mN1MS25-YI_MqTBs_DwMhMoJhL2ddITRjY32QQ7E1o8GA2))/

This means that the browser sees the cookieless information as part of the directory structure for the site. If you embed relative URLs into your page such as:

<a href=SomeOtherPage.aspx>Click me. I’m a regular A tag.</a>

Then whenever you click these types of links, the browser will prepend it with the current path information from the current page. So, this <a /> tag is interpreted by the browser as:

216

Forms Authentication

http://demotest/Chapter5/cookieless/(X(1)F(BS3d6LKEP5D74Rw6F2Lq1n- O9Ot6jzkZQpYhhHDW9mN1MS25-YI_MqTBs_DwMhMoJhL2ddITRjY32QQ7E1o8GA2))/SomeOtherPage.as px

On the other hand, if you embed absolute hrefs in your pages, then you will lose the forms authentication ticket when someone clicks on the link. For example, if you accidentally created the <a/> tag as:

<a href=”/SomeOtherPage.aspx”>Click me. I’m a regular A tag.</a>

The address that your browser will navigate to is:

http://demotest/SomeOtherPage.aspx

With this style of URL, you can see that the forms authentication ticket is lost. Now for a simple application, you may not need to use absolute URLs. However, if you have a more complex navigation structure, perhaps with a common menu or navigation bar on your pages, you may very well have a set of fixed URLs that users can click. Unfortunately, cookieless forms authentication and absolute URLs do not mix, so you will need to write extra code to account for this behavior. Although a bit kludgy, an easy way to maintain a common set of URL endpoints like this is with a redirection page.

Instead of the browser “knowing” the correct endpoint URL that it should navigate to, you can convert these types of links into GET requests against a common redirection page. For example, you can use the LinkButton control to postback to ASP.NET:

<asp:LinkButton ID=”linkRedirectMe” runat=”server” OnClick=”linkRedirectMe_Click”>

SomeOtherPage </asp:LinkButton>

In the code-behind, the click event looks like:

Response.Redirect(“~/SomeOtherPage.aspx”);

Now when you click the link the browser, the page posts back to ASP.NET, and a server-side redirect is issued that retains the entire cookieless information in the URL. The reason server-side redirects work is that Response.Redirect includes extra logic that ensures all of the information in the custom HTTP_ASPFILTERSESSIONID HTTP header (remember this is where the cookieless information is moved to on each request by aspnet_filter.dll) is added back into the URL that is sent back to the browser. When the redirect reaches the browser, it has the full URL including the cookieless tickets.

One last area where URL format matters is in any postback event references in the page. In fact, the LinkButton example depended on the correct behavior when posting the page back to itself. Because just about every ASP.NET control depends on postbacks, it would be pretty painful if postbacks did not correctly retain all cookieless tickets. ASP.NET is able to retain the cookieless tickets by explicitly embedding them in the “action” tag of the page’s <form /> element. Taking the previous LinkButton example, if you view the source of the page in the browser, the form element looks like:

<form method=”post” action=”/Chapter5/cookieless/(X(1)F(BS3d6LKEP5D74Rw6F2Lq1n- O9Ot6jzkZQpYhhHDW9mN1MS25-YI_MqTBs_DwMhMoJhL2ddITRjY32QQ7E1o8GA2))/default.aspx” id=”form1”>

217

Chapter 5

Because much of the postback infrastructure depends on calling the JavaScript submit() method of a form, and the action attribute on the form includes the cookieless information, any attempt to programmatically submit a form (whether this is ASP.NET code or JavaScript code that you write) will include the cookieless information.

Overall ASP.NET will, for the most part, correctly retain the cookieless tickets in a transparent manner. Only if you embed absolute URLs in your pages, or if you use absolute URLs in your code-behind will you lose the cookieless tickets. You should try to use relative URLs in page markup, and application-relative URLs in code-behind and for attributes of ASP.NET server controls. Although there are cases in server-side code where you can write code with URLs that are absolute virtual paths (that is, /myapproot/somepage

.aspx), depending on whether you use this style of URL with Response.Redirect versus in a control property, you will get different behavior. Coding with application-relative URLs (that is, ~/somepage

.aspx) gives you consistent behavior with cookieless tickets regardless of where you use the applicationrelative URL. The following table shows various pieces of code and whether or not cookieless tickets are preserved.

Code That Uses URLs

Are Tickets Retained?

 

 

Response.Redirect(“~/SomeOtherPage.aspx”);

Yes

Response.Redirect(“SomeOtherPage.aspx”);

Yes

Response.Redirect(“/Chapter5/cookieless/

Yes

SomeOtherPage.aspx”);

 

Response.Redirect(“http://demotest/Chapter5/

No

cookieless/SomeOtherPage.aspx”);

 

<asp:HyperLink ID=”HyperLink1” runat=”server”

Yes

NavigateUrl=”~/SomeOtherPage.aspx”>

 

<asp:HyperLink ID=”HyperLink2” runat=”server”

No

NavigateUrl=”/Chapter5/cookieless/

 

SomeOtherPage.aspx”>

 

<a href=SomeOtherPage.aspx>

Yes

<a href=”/SomeOtherPage.aspx”>

No

 

 

Payload Size with Cookieless Tickets

When you support cookieless tickets with forms authentication, you need to be careful of the size of the forms authentication ticket in the URL. Although forms authentication in cookie mode technically also has issues with the size of the ticket, you have roughly 4K of data that you can work with in cookied mode. However, in cookieless mode there are two factors that work against you and limit the overall amount of data that you can place in a FormsAuthenticationTicket:

There are other cookieless features in ASP.NET that also may place cookieless identifiers on the URL. Both session state and anonymous identification can take up space in the URL.

On IIS6, you cannot have more than 260 characters in any individual path segment (assuming that you don’t change the registry settings that control http.sys).

218

Forms Authentication

If you think about it, the 260-character constraint is actually pretty limiting and basically means that little more than username and expiration date can be effectively shipped around in a cookieless ticket. The previous sections on cookieless tickets regularly resulted in around 100 or more characters being used on the URL for the ticket.

You can turn on anonymous identification and session state in web.config, and force them to run in cookieless mode with the following configuration settings (they use the same values for the cookieless attribute as forms authentication):

<anonymousIdentification enabled=”true” cookieless=”UseUri”/>

<sessionState cookieless=”UseUri” />

Without even logging in to a sample application with these settings, the URL includes the following cookieless tickets (assume auto-detection is used for forms authentication for the absolute worst-case scenario).

(

X(1)

A(AcWPai80EudiMDgzMTVmOC01ZGI4LTRjYjUtYTRlZC1lNDA0ZmQwMTgwOWapA57PN8DjUYXzLE05vMg

q89nYDg2)

S(kabdwb45w2casiv3hlrqdd55)

)

Adding this all up, and ignoring the line breaks because those exist just for formatting in the book, there are:

2 characters for the beginning and closing parentheses

4 characters for the auto-detection marker “X”

90 characters for the anonymous identification ticket “A”

27 characters for the session state identifier “S”

Without forms authentication even being involved, ASP.NET has already consumed 123 characters on the URL, which leaves a paltry 137 characters for forms authentication.

The most obvious piece of information that drives variability in the size of the forms authentication ticket is the username. You may not realize it, but the value of the path configuration attribute could also contribute to the variable size of the ticket. By default the path is set to /, so this only adds one additional character to the ticket prior to its encryption. In cookieless mode though, because the ticket is embedded in the URL, there isn’t really a concept of path information. As a result, in cookieless mode the path is always set to / by forms authentication, and hence there is always the same overhead in cookieless tickets for the path value.

Other information such as a ticket version number and the issue and expiration date information are fixed size and doesn’t vary from one website to another. Logging in to a sample application with a comparatively short username (testuser), adds the following forms authentication ticket to the URL:

F(JUBYnKzy-aTgVpRkDRmQRCU_dlcEF4pnfdxoYl75NEdnl3mjJw8w7fH1XbFGupwrQp7T5jAO- 1qZzp3VG8bguDYDjru1_V9xO0DfqtK0LZA1)

219

Chapter 5

This adds another whopping 112 characters to the URL for a total size. Now with all cookieless features enabled there are 235 characters consumed for the various cookieless representations. Playing around a bit with different usernames on the sample application, the longest username that worked was testuser123456789012 — that is, a 20-character long username. This results in an F ticket that is

132 characters long — resulting in a path segment that is 255 characters long. That is right on the edge of the 260 character path segment limit enforced by http.sys.

After the username increases to 21 characters, a 400 Bad Request error is returned. If you recall the discussion about http.sys from Chapter 1, a 400 error is returned by http.sys when one of the path segments in the request URL is more than 260-characters long.

Going back to the path configuration attribute, you can explicitly set it to match the application’s root:

<forms cookieless=”AutoDetect” path=”/Chapter5/cookieless” />

Logging with just testuser for the username results in a 112-character length for the forms authentication cookieless ticket (the same as before). And as before, the upper limit on the username is 20 characters. If you are curious what happened to the path information from configuration, the value of FormsAuthenticationTicket.CookiePath is hard-coded to /, regardless of the value in configuration. At one point earlier in the ASP.NET 2.0 development cycle, the full path value from configuration was included in cookieless tickets. Because this consumed far too much space on the URL (you could come up with a long enough path that even a zero-length username was too much to fit in the URL), the decision was made to always use the hard-coded / value. Keep this quirk in mind if for any reason you were depending on the FormsAuthenticationTicket.CookiePath property anywhere in your code — it should not be relied upon if your application ever issues cookieless forms authentication tickets.

Of course, the size constraints on the URL are a bit more relaxed if you don’t use other cookieless features. Turning off anonymous identification (because that is gobbling up 90 characters), a 40-character long username results in around a 230-character long URL. Because 40-character usernames are pretty unlikely, you have breathing room on the URL after anonymous identification is disabled.

If you use cookieless forms authentication tickets, keep the following points in mind:

With all cookieless features turned on, you are limited to around a maximum length of 20 characters for usernames with forms authentication.

With anonymous identification turned off, you will probably not run into any real-world constraints on username length, unless of course you allow email addresses for usernames. Because email addresses can be upwards of 256 characters long, you will need to limit username length for such applications.

One final point on how cookieless tickets embedded in the URL: even though ASP.NET 2.0 embeds them all into a single path segment, future releases may choose to split out the cookieless tickets for various features into separate path segments. If this approach is ever taken, it would free up quite a bit more space for forms authentication — enough space that even UserData could potentially store limited amounts of information. For this reason, I would recommend that developers avoid writing code that explicitly parses the URL format used by ASP.NET 2.0 or that depends on the specific layout of cookieless tickets. Continue to manipulate URLs with the built-in ASP.NET APIs and the application-relative path syntax. Writing code that has an explicit dependency on the ASP.NET 2.0 cookieless format may lead to the need to rework such code in future releases.

220

Forms Authentication

Unexpected Redirect Behavior

Cookieless forms authentication introduces another subtle gotcha due to the reliance on redirects. The initial set of redirects that occur during autodetection don’t complicate matters because this logic runs as part of the normal redirection to a login page. In existing ASP.NET 1.1 applications, developers already have to deal with the possibility of a website user posting data back to a secured page, only to get redirected to the login page instead — along with the subsequent loss of any posted data.

However a bit of an edge case arises when using cookieless tickets, regardless of the selected cookieless mode. If you allow sliding expirations with cookieless tickets (and for security reasons this is not advised), then it is possible that at some point FormsAuthenticationModule may detect that more than 50% of a ticket’s lifetime has elapsed. The module always calls FormsAuthentication.RenewTicketIfOld on each request, for both cookied and cookieless modes. In the case of cookieless modes though, if the module detects that a new forms authentication ticket was issued with an updated expiration time due to the renewal call, the module needs to ensure that the new ticket value is embedded on the URL.

The module accomplishes this by repackaging the new FormsAuthenticationTicket into the custom HTTP_ASPFILTERSESSIONID header and then calling Response.Redirect , specifically the overload of Response.Redirect that accepts only the redirect path. This means the current request is immediately short-circuited to the EndRequest phase of the pipeline, and the redirect with the updated URL is sent back to the browser.

From the user’s perspective, this means that at anytime the user is working in the website (and this can be on a secured page or a publicly accessible page), enough of the ticket expiration may have elapsed to trigger a redirect. If by happenstance this redirect occurs when posting back user-entered data, the user is going to be one unhappy camper. Imagine entering a form full of registration data, hitting submit, and the net result is that you end up back on the same page with all of the fields showing as empty!

You can simulate this behavior with a simple page that has a few text boxes for entering data. Add a button that posts the page back to the server. Set the timeout attribute in the <forms /> configuration element to 2 minutes. Log in to the site, and navigate to the page with the text boxes. Type in some data, and then wait around 1.5 minutes, long enough for the ticket to need renewal. Now when you post back, you can see that all of the data you entered has been lost. This behavior is another reason why sliding expirations should be avoided when using cookieless tickets.

About the only workaround (and an admittedly crude one at that) is for developers to identify pages in their site where user-entered information is not posted back in a form variable. For example, maybe viewing a catalog page in a website relies on query-string variables and a GET request, which allows the query-string variables to be preserved across redirects. You can write some code that runs in the pipeline (after FormsAuthenticationModule runs) and pro-actively checks the expiration date of the ticket. Rather than waiting for the ASP.NET default of 50% or more of the ticket lifetime to elapse, you could be more aggressive and force a ticket to be reissued at shorter intervals. This at least gives you some control over when the ticket is reissued, and it increases the likelihood that the ticket is reissued at well-defined points in the website where you can be assured that user-entered data is not lost.

221