I am using Asp.Net Membership and when user enters correct username and password I sign him in using:
FormsAuthentication.SetAuthCookie(String, Boolean)
If I create a persistent cookie then I think my membership will still be able to work but my session data will be null.
This is really annonying and introducing a whole lot of bugs in my application. How can I handle this?
Should I handle global.asax's Application_AuthenticateRequest and check if the userId which I store in session is null and Membership.GetUser() is not null, then I should store ProviderUserKey (Guid) again in Session.
Is this a reasonable approach or is there any better way of handling this?
You must configure your session and authcookie's life-time in your web.config file. See:
<forms timeout="5" />
<sessionState timeout="5" />
Forms are used for authentication and when it times out it will logout
user. You can 'prevent' timeout by setting SlidingExpiration property
to 'true' and it will renew forms ticket on user activity (read
request to asp) if needed. This will keep user logged on while he is
'active' on your site.
and
When session times out you will lose data found in Session object.
Your problem may may be of this issue. Your auth-cookie is alive, but the session is timed-out. User is logged-in, but the session-variables are destroyed! Check this configuration in your app.
See this Q also
I think, you need to use session for it instead of cookie.
And according to me that should be not preferable to save ProviderUserKey in session or any where.
Use global.asax(Application_AuthenticateRequest) for check authentication and based on that id, get ProviderUserKey from DB.
Hope my comment is useful for you.
sessions and authcookies are different. authcookies life-time can be set in forms timeout="5" config-section and sessions life-time should be set in sessionState timeout="5" config-section. It is possible that an auth-cookie is persist yet, but the session expires. Check this.
Related
I have an asp.net web form. when a user authenticate, it create a Secured cookie called .aspxauth
uppon logout, I call these 2 methods
FormsAuthentication.SignOut();
Session.Abandon()
Problem is that we had penetration test and if I steal the cookie, logout and manually reinsert the cookie, I become loggued in again. So the .aspauth isn't invalidated server side.
I've googled it and I can't find the answer to that security breach.
Microsoft has acknowledged this issue here: https://support.microsoft.com/en-us/kb/900111
They offer several ideas for mitigating this vulnerability:
protect the application by using SSL
Enforce TTL and absolute expiration
Use HttpOnly cookies and forms authentication in ASP.NET 2.0
Use the Membership class in ASP.NET 2.0
Regarding the last one, I'll paste the contents from the site for convenience/preservation:
When you implement forms authentication in ASP.NET 2.0, you have the option of storing user information in a Membership provider. This option is a new feature that is introduced in ASP.NET 2.0. The MembershipUser object contains specific users.
If the user is logged in, you can store this information in the Comment property of the MembershipUser object. If you use this property, you can develop a mechanism to reduce cookie replay issues in ASP.NET 2.0. This mechanism would follow these steps:
You create an HttpModule that hooks the PostAuthenticateRequest event.
If a FormsIdentity object is in the HttpContext.User property, the FormsAuthenticationModule class recognizes the forms authentication ticket as valid.
Then, the custom HttpModule class obtains a reference to the MembershipUser instance that is associated with the authenticated user.
You examine the Comment property to determine whether the user is currently logged in.
Important: You must store information in the Comment property that indicates when the user explicitly signed out. Also, you must clear the information that is in the Comment property when the customer eventually signs in again.
If the user is not currently logged in as indicated by the Comment property, you must take the following actions:
Clear the cookie.
Set the Response.Status property to 401.
Make a call to the Response.End method that will implicitly redirect the request to the logon page.
By using this method, the forms authentication cookie will only be accepted if the user has not been explicitly signed out and the forms authentication ticket has not yet expired.
Read this article about Session fixation and how to get rid of it once and for all:
http://www.dotnetfunda.com/articles/show/1395/how-to-avoid-the-session-fixation-vulnerability-in-aspnet
This remains an issue in .NET Framework. Everyone seems to think Session.Abandon() is the answer, but the sad truth is that command does not invalidate the session on the server's side. Anyone with the right token value can still resurrect a dead session, until the session expires based on the Web.config settings (default = 20minutes).
A similar questioner posed this question a long time ago here:
Session Fixation in ASP.NET
Most of those links are dead, and Microsoft has no new news on the topic.
https://forums.asp.net/t/2154458.aspx?Preventing+Cookie+Replay+Attacks+MS+support+article+is+now+a+dead+link
Worse still, you're still vulnerable to this cookie replay attack even if you're implementing a completely stateless MVC application and don't use the Session object to store data between views. You can even turn off session state in the web.config settings and still replay cookies to gain access to a logged-out session.
The true solution is hack-y and described here, and you need to have session data enabled InProc to use it.
When the user logs in, set a boolean value in the session data, like Session["LoggedIn"] = true;, which is stored on the server side.
When the user logs out, set that value to false.
Check the session value on every request--an attacker trying to replay a session isn't going to be nice to you and come in through the Login page only. It's probably easiest to do this using a custom filter and registering it globally in the global.asax file (so you don't have to duplicate the code everywhere, or attribute every controller/method).
Even if the attacker has all the cookie values, they won't be able to re-use that same session ID, and the server will automatically delete it once it reaches the specified timeout.
if you are using the FormsAuthentication, you can use this code. By using this code you can destroy the created cookies by setting the Expire property of HttpCookie. It will help you:
FormsAuthentication.SignOut();
Session.Clear();
Session.Abandon();
Session.RemoveAll();
// clear authentication cookie
HttpCookie httpCookie = new HttpCookie(FormsAuthentication.FormsCookieName, "");
httpCookie.Expires = DateTime.Now.AddYears(-1);
Response.Cookies.Add(httpCookie);
I am very confused in my implementation of sessions in asp.net web application. My logic is once user enters user name+password, I validate credentials and then create a new session with some user info[All I am after from this point onward is that this user has access to restricted resources and a user must never be able to access those resources unless he/she is authenticated]. This I validate on each request and the rest. Here is my issue though. I have many places in the website where I have html links, and I read that if I have a link such as
<a href='resource1.aspx'>resource 1</a>
This will generate a new session id, hence in reality invalidating the existing session id, which in my case will be treated as session expired and user is sent to login page. While reading up on this issue I came across an asp.net API method[
Response.ApplyAppPathModifier(url);
] which prepends the session id to each request hence resolving the new session id generation for each link. Though it resolves session breaking issue it does add the session id next to all of the urls and now session id can be seen in the source code( view source for web page). I really don't want to use cookies and want to use session for user sessions...Can some one please help me create a system which will work the way I wish it to ? if I am doing it utterly incorrect, I would really really appreciate a details discussion and if possible some example...Thanks you much in advance..
It looks like you are trying to use cookieless sessions which add a session id to all links in order to be able to track the sessions.
The other (much more common, standard and IMO secure) approach is to use normal sessions, which auto creates a session cookie (when you use the .Session object), and uses that to determin the current session. If you don't want a cookie you'll have to stick with cookieless, and the session id in the url.
We are using the Simple Membership Provider with ASP.NET MVC 4, and we're using the Facebook Client to provide Facebook login support (similar to http://www.asp.net/mvc/overview/getting-started/using-oauth-providers-with-mvc).
We have gotten this working, but the session always times out within a day, and we want the login to be persistent, so the user can login and use the service just once.
In the out-of-the-box ExternalLoginCallback function, I am attempting to set the createPersistentCookie parameter to true, but it won't keep the login alive. Here is the call I am making:
OAuthWebSecurity.Login(result.Provider, result.ProviderUserId, createPersistentCookie: true)
Am I going to have to set the Forms Authentication cookie manually in order to accomplish a persistent login? Or is there another way of doing this while still taking advantage of the out-of-the-box Facebook login functionality?
The ASPXAUTH cookie is used to determine if a user is authenticated. You can track expiration time with firebug or any other web debug tool. In your project the cookie is set in ExternalLoginCallback. Here is example screen setting cookies' expiration timeout.
All what I had to do to make it work was to use SSL, and change cookie timeout in web.config. Here is example with timeout set to 1 minute. Don't forget to mark requireSSL on true.
<authentication mode="Forms">
<forms loginUrl="~/Account/Login" timeout="1" requireSSL="true"/>
</authentication>
But in your case i believe the problem is with short live access token from facebook(default around 2h). In case if the problem is with access token here is link how to extend lifetime of access token.
I've got 2 MVC3 Internet websites. One (Site1) uses Windows authentication and is in the Local Intranet Zone. The second (Site2) is publicly available and uses Forms Authentication. Both sites are in the same Domain, but have a different sub-domain. I want to share authentication cookies between the two. In order to do this, they need identical settings in the web config. Sometimes this works, most of the time it doesn't. If anyone hits Site1 from outside our network, they get a 403 error, which is good. If a network user hits Site1, they're allowed in based on their network credentials. I then check their user's roles with the code below.
var userName = string.Empty;
var winId = (WindowsIdentity)HttpContext.User.Identity;
var winPrincipal = new WindowsPrincipal(winId);
if(winPrincipal.IsInRole("SiteAdmin")) {
FormsAuthentication.SetAuthCookie("siteadmin", false);
userName = "siteadmin"; //This is a Forms Auth user
}
else if(///I check for other roles here and assign like above)
Once I've checked the roles, I forward them onto Site2, creating a cookie for them if the user is in one of the roles determined in the if...statement above.
if(!string.IsNullOrEmpty(userName)) {
//Add a cookie that Site2 will use for Authentication
var cookie = FormsAuthentication.GetAuthCookie(userName, false);
cookie.Domain = FormsAuthentication.CookieDomain; //This may need to be changed to actually set the Domain to the Domain of the TVAP site.
HttpContext.Response.Cookies.Add(cookie);
}
//Network users not found in roles will simply be forwarded without a cookie and have to login
HttpContext.Response.RedirectPermanent(tvapUrl);
I've set up in the web.config a matching MachineKey (validationkey, decryptionkey and validation) for each site.
They also both have the same authentiation settings, with the exception of the mode. So my config for this looks like this.
<authentication mode="Forms">
<forms loginUrl="~/Account/LogOn" name=".ASPXFORMSAUTH" protection="All" path="/" domain="mydomain.com" enableCrossAppRedirects="true" timeout="2880" />
</authentication>
I think my problem is that the 'authentication' mode is different for each one, so Site2 won't use the authentication cookie from site1. This is just a guess though. Is there anyway I can figure out the issue?
According to this article, what I have going here should work. And there have been times where I think it's worked, but it's hard to tell, as I may have cookies cached and their getting reused. I'm hoping someone can see something I'm missing here, or has an alternative solution.
UPDATE
I checked my authentication cookie on Site2 after logging in normally and found the Domain wasn't set, so I've removed that line of code.
Also, I read about cookies expiring when the date isn't set, so I set an Expire Date on my cookie before sending with the request.
So, with those two changes, here's where I'm at.
It works on Chrome and Firefox, but not with IE. Not sure. I'm going to do some additional testing from another machine and another user so I know I haven't got any residual cookies sitting around.
I determined my problem was not setting the Expires property of my cookie. According this Microsoft article, cookies won't be written to the client unless the Expires property is set.
"If you do not set the cookie's expiration, the cookie is created but it is not stored on the user's hard disk. Instead, the cookie is maintained as part of the user's session information. When the user closes the browser, the cookie is discarded. A non-persistent cookie like this is useful for information that needs to be stored for only a short time or that for security reasons should not be written to disk on the client computer. For example, non-persistent cookies are useful if the user is working on a public computer, where you do not want to write the cookie to disk."
In this case, I needed the cookie to be written to disk since I was doing a server transfer to another site, thereby ending the session for that user. I'm not 100% sure that this was the fix, but it is working now, so I'm assuming that.
I am developing the application that stores current user and user's role to session state (System.Web.SessionState.HttpSessionState Page.Session).
if (Session["username"] == null)
Session.Add("username", User.Identity.Name);
if (Session["isAdministrator"] == null)
Session.Add("isAdministrator", User.IsInRole(domain + "\\Domain Admins"));
After I check these session states in code behind for granting permissions to some excecution:
if ((bool)Session["isAdministrator"] || computer.Administrators.Contains(Session["username"].ToString()))
My question is next: how safe that mechanism is? Is it possible to change the session states using some JavaScript for example or some how else?
Thanks :)
If User.Identity.Name is set, why do you need to put it in the Session? Why don't you just call User.IsInRole(domain + "\\Domain Admins") directly (or wrap it in a helper)? It looks to me like you're using Windows Authentication, so setting the username in the session is redundant.
As for your XSS question, the session stores the session ID in a cookie, so in theory an attacker could be sniffing the HTTP traffic or inject JavaScript code into your pages, get a hold of the cookie, then use it and impersonate another user.
It is not possible to change the session state using javascript or other client-side mechanisms, as the state is only stored on the server. However, it is, as others have pointed out, possible for a malicious user to hijack a session by getting hold of the contents of the session cookie.
ASP.NET is designed with this weakness in mind - the session ID is suitably long and hard to predict. Also, the session cookie is marked as HTTP ONLY, which means that most modern browsers will not allow javascript code to access it.
In general I would say this is very safe from XSS attacks. ASP.Net, by default, tracks a users session based on a Cookie which contains the users session ID. You can see this if you open your browsers cookie list and look for ones from your site, there will be one there named ASP.Net Session something... The SessionID's unique, and not incremental. Probably some variance of a GUID.
For added security you can also specify, in your web.config, how long to keep a users session alive. If you are dealing with sensitive information you might want to set this timeout to be relatively short period of time, maybe 10 minutes of inactivity, the default is 20 minutes. You can find more info # http://msdn.microsoft.com/en-us/library/system.web.sessionstate.httpsessionstate.timeout.aspx.
<system.web>
<sessionState timeout="10" />
</system.web>
--Peter