Scott on Writing

Musings on technical writing...

A Potential Security Hole with "Remember Me Next Time"

When a user authenticates in ASP.NET using forms authentication, the forms authentication system writes an authentication ticket to the user's cookies that allows the site to remember that the user has already been authenticated. This authentication ticket either lasts for the duration of the user's visit, for a specified duration, or can be persisted on the user's machine. If a timeout is specified, it can be a sliding or absolute duration. To specify this duration, from Web.config use the <forms> element's timeout and slidingExpiration attributes. It's a little confusing because the rules governing the cookie expiry changed between ASP.NET 1.x and 2.0.

In ASP.NET 1.x, the timeout settings are ignored for persistent cookies. For ASP.NET 2.0, the timeout settings only apply to the persistent cookies. Moreover, in ASP.NET 1.x the expiry defaults to be sliding, while in ASP.NET 2.0 it defaults to be absolute.

What this means, in English, is that in ASP.NET 1.x if you created a non-persistent authentication ticket cookie, it would last for the specified timeout (default is 30 minutes) with the timeout automatically being refreshed each time the user visited a new page in the site. In short, if a user visited a site, logged on (but did not choose to have their credentials remembered for subsequent visits), the cookie would be good until the user let 30 minutes (or whatever) lapse between visiting the site. If the user logged on with a persistent cookie, the cookie would have a duration of 50 years! Crazy. This, as we'll discuss shortly, carries with it some security concerns.

ASP.NET 2.0 takes a much more conservative approach toward authentication ticket cookie expiries. For non-persistent cookies, the cookie lasts for the duration that the browser's open. There's no timeout, but once the browser closes, the user will need to re-authenticate when the next visit the site. Persistent cookies have an expiry based on the timeout value (again, a default of 30) and it defaults to an absolute timeout, meaning that after 30 minutes, regardless of how often they hit the site, the user will have to reauthenticate. This settings, of course, can be changed through the <forms> element as noted above.

The authentication ticket is persisted on the user's machine across browser restarts (but only for the specified timeout duration) in ASP.NET 2.0 if the Login control's “Remember me next time” checkbox is checked. One potential security hole here is introduced because of the disconnect between authentication and the user's underlying information in the Membership system (or in some custom user store system). Consider the following scenario:

  • User A logs into site and checks “Remember me next time“. Imagine that the site has a timeout of three days.
  • User A then posts messages to the forum on this site and blasts a lot of spam and other garbage
  • Mr. Administrator sets User A's IsApproved value to False. If the user goes to Login.aspx, they won't be able to validate their credentials, but............
  • User A has a persistent authentication ticket cookie on his machine that is good for three days. So if User A visits tomorrow, he's still able to pass the authorization checks. If there's no additional logic on making posts that ensures the poster is approved, blam, User A is back to making his garbage posts.

Any suggestions/recommendations on preventing this? I see two options:

  1. The application should not allow posts from unapproved users. Such a check could be done right before the post is committed to the database, for instance. This would prevent an unapproved user from making a post, but would still let them get on the site via the persistent authentication ticket cookie (until it expired after three days).
  2. Use a Session variable to indicate if a user has had their Approved status validated. If so, do nothing. If not, then check Membership.GetUser().IsApproved to make sure it has a value of True. If it does, set the Session variable to indicate that the check has been performed. In a base page class, override OnInit and perform this logic. Then have all ASP.NET pages in sections where only authenticated users are allowed derive from this base page class so that all pages make sure that the users visiting the site are approved.

Any other suggestions or workarounds for this issue? Granted, one could simply shorten the persistent cookie timeout, but that kind of defeats the utility of “Remember me next time.” The good news is that because ASP.NET 2.0 is much more conservative than ASP.NET 1.x by default, the window with which an unapproved user has to access the site is greatly reduced.

posted on Thursday, February 01, 2007 12:13 PM

Feedback

# re: A Potential Security Hole with "Remember Me Next Time" 2/1/2007 2:08 PM Kiliman

How about adding the following in Global.asax or an HttpModule? It the user is already authenticated (via the persistent cookie), it will double check the Membership user to verify the user is active.

Hopefully the code looks decent in the comment.


protected void Application_AuthenticateRequest(object sender, EventArgs e)
{
if (HttpContext.Current.User != null && HttpContext.Current.User.Identity.IsAuthenticated)
{
MembershipUser u = Membership.GetUser();
if (!u.IsApproved || u.IsLockedOut)
{
FormsAuthentication.SignOut();
FormsAuthentication.RedirectToLoginPage();
}
}
}


Kiliman

# re: A Potential Security Hole with "Remember Me Next Time" 2/2/2007 1:40 AM Pradeep

Thanks for this information! :)

# re: A Potential Security Hole with "Remember Me Next Time" 2/2/2007 5:58 PM Scott Mitchell

Kiliman, your code is going to run EVERY page visit. If you are using the SqlMembershipProvider, Membership.GetUser() hits the database.

So I think it might be a step in the right direction, but I still think you would want to us a Session variable or some other form of remembering whether or not the user's approved status has been recently validated.

# Membership.GetUser() vs Session variables 2/6/2007 10:51 AM Deathtospam

Scott --

Is the use of a Session variable going to be any less expensive than calling Membership.GetUser() on each page? Anyway, I do agree with your general sentiment: there probably is a more efficient way to perform the type of check Kiliman posted about.


-= Deathtospam =-

# re: A Potential Security Hole with "Remember Me Next Time" 2/6/2007 11:02 AM Scott Mitchell

Deathtospam, the Membership.GetUser(), if you are using the SqlMembershipProvider, will make a call to the database, whereas the Session variable is just reading from the web server's memory. So there's probably an order of magnitude (or greater) in the performance difference between the two.

Title:  
Name:  
Url:
Protected by Clearscreen.SharpHIPEnter the code you see:
Comments   

Add To Your Reader

My Links

Archives

Post Categories

 

I am a Microsoft MVP for ASP.NET.
I am an ASPInsider.
<May 2008>
SMTWTFS
27282930123
45678910
11121314151617
18192021222324
25262728293031
1234567

Comment Stats

DayTotal% of Total
Sunday 1866.8%
Monday 37913.9%
Tuesday 45316.7%
Wednesday 50418.5%
Thursday 53519.7%
Friday 49418.2%
Saturday 1666.1%
Total 2717100.0%

Hour1Total% of Total
12:00 AM 652.4%
1:00 AM 682.5%
2:00 AM 622.3%
3:00 AM 742.7%
4:00 AM 572.1%
5:00 AM 1033.8%
6:00 AM 1084.0%
7:00 AM 1585.8%
8:00 AM 1716.3%
9:00 AM 1475.4%
10:00 AM 1716.3%
11:00 AM 1816.7%
12:00 PM 1886.9%
1:00 PM 1696.2%
2:00 PM 1605.9%
3:00 PM 1324.9%
4:00 PM 1073.9%
5:00 PM 923.4%
6:00 PM 913.3%
7:00 PM 963.5%
8:00 PM 833.1%
9:00 PM 782.9%
10:00 PM 792.9%
11:00 PM 772.8%
Total 2717100.0%

Comments by Blog Entry Date/Time

Day Entry MadeAvg.Total
Sunday 5.54144
Monday 5.22339
Tuesday 4.28419
Wednesday 7.67637
Thursday 6.90607
Friday 5.48411
Saturday 5.33160
Total 5.842717

Hour1 Entry MadeAvg.Total
12:00 AM 5.0035
1:00 AM 1.002
5:00 AM 0.000
7:00 AM 7.0035
8:00 AM 5.35107
9:00 AM 6.32278
10:00 AM 6.47246
11:00 AM 4.41181
12:00 PM 6.88330
1:00 PM 3.00111
2:00 PM 5.41222
3:00 PM 8.64285
4:00 PM 4.0589
5:00 PM 5.92154
6:00 PM 4.52113
7:00 PM 9.67174
8:00 PM 9.80147
9:00 PM 5.05111
10:00 PM 5.4265
11:00 PM 4.5732
Total 5.842717

Learn More About Comment Stats
1 - All times GMT -8...


Blog Stats

Favorite Web Sites

My Books

My MSDN Articles