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.
Related
I'm developing a .NET MVC web application in C# which implements form authentication.
I have the below configuration in my web.config file:
<authentication mode="Forms">
<forms loginUrl="~/Home/Register" timeout="10080" name="Test" slidingExpiration="true"/>
</authentication>
<sessionState cookieName="Test" timeout="5040"/>
I have some questions:
Using the same name for session state cookie name and form cookie name is OK or it will cause problems/collisions for the parameters such as timeout?
Setting slidingExpiration="true" causes renewal of timeout automatically or it requires calling some special function on the backend?
I have read the second comment of this answer: https://stackoverflow.com/a/17813200/1080355. So I set the form auth cookie time out twice of session time out. I'm doing it in the right manner?
Setting same name for both cookies will cause issues, please avoid it, set unique names for both cookies
Cookie will be renewed automatically but of course only upon a request. As long as there are no requests from the browser, there's nothing to renew. Renewal consists in just issuing a new cookie that overwrites the old one.
Edit: Not sure why this is not clear. Maybe this will help: browser makes a request, server finds out that cookie is valid but it's about to expire. So the server issues a new cookie. Formally, it's the forms authentication module that does so, automatically,.
Forms cookie timeout and session state timeout are completely unrelated and there's no rule that would make one dependant on the other.
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);
ASP.NET Web Forms applications.
I checked our company's legacy code, the way they do login is like this:
when user is validated against database with (username, password), they set a session:
Session["authenticated"] = "true";
Every page other than login.aspx is inherited from a class named SecurePage. In SecurePage's OnInit() method, it checks
if (Session["authenticated"] != null)
if true, means authenticated, otherwise means not. So basically the way to do authentication is to see if there is a session named authenticated.
This seems the most crude and intuitive way of doing authentication... I want to ask: is this safe?
Another thing I feel strange is that in the web.config, they have this:
<authentication mode="Windows" />
Shouldn't it be
<authentication mode="Forms" />
since these are web applications? Users credentials are stored in database and these users are outside clients (not internal users).
A slight different version also does this after user is validated against database:
FormsAuthentication.SetAuthCookie( username, true );
what does this do? Besides this statement in login.aspx, I don't see any other pages have any code related to auth cookie. Do we need to set auth cookie by ourselves in code or does .NET framework handle this for us already?
Still another version have the following:
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(login, false, 60);
HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, FormsAuthentication.Encrypt(ticket));
Response.Cookies.Add(cookie);
what does this do? Do we need to set this cookie by ourselves in code? or does .NET framework handle this for us already?
These web appliations were developed a long time ago, though I am not sure when. I suspect it is .NET 1.0 era? From my understanding since .NET 2.0,
it has this ASP.NET membership thing, and we can just use <authentication> and <authorization> tags in web.config (and subfolder web.config) to achieve the goal of authentication and authorization. Isn't it? Can anyone give me a history of ASP.NET framework authentiation mechanism? (membership -> simple memebership -> Identity?)
<authentication mode="Windows" />
Above should be used mostly in intranet website, because it's like saying use the computer(windows pc) authentication to access the resource. However, this will never work, since inherited class has a method to validate session key value for a login.
You should make sure that the code redirects user to login page in case the session key is not found. That means, in the else section of below code, you should take users to login page to try again. Which I am sure is happening.
if (Session["authenticated"] != null)
{ /*user is authenticated*/ }else{ /*redirect to login*/ }
Its is recommended to use <authentication mode="Forms" /> if the website is accessible over the internet. Other benefit of using this setting is that you can set default and login page.
Finally, FormsAuthenticationTicket is a class with property and values that are used when working with Forms authentication to identify authenticated users.
Read through msdn article to know more about asp.net membership.
https://msdn.microsoft.com/en-us/library/yh26yfzy%28v=vs.140%29.aspx
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.
Q1
I’ve read that when setting the timeout of an authentication cookie, we should keep in mind that the longer the cookie persists, the greater the chance of a cookie being stolen and misused.
A) But assuming we secure our application against replay attacks by enabling SSL for the entire application, and since forms authentication module also encrypts authentication data in authentication cookie, then I would think there is no chance of this cookie being misused and thus cookies being persisted for longer periods of time should not present any security risks?!
Q2
FormsAuthentication.FormsCookiePath specifies where authentication cookie is stored. Default value is ‘/’.
A) Assuming default value ’/’ is used, where is cookie saved then?
B) Is this option only used for persistent cookies?
thanx
2A The cookie path is the path on the server the cookie relates to, not the path where the cookie is store.
From http://www.quirksmode.org/js/cookies.html
The path gives you the chance to specify a directory where the cookie is active. So if you want the cookie to be only sent to pages in the directory cgi-bin, set the path to /cgi-bin. Usually the path is set to /, which means the cookie is valid throughout the entire domain.
This script does so, so the cookies you can set on this page will be sent to any page in the www.quirksmode.org domain (though only this page has a script that searches for the cookies and does something with them).
You are using ASP.Net. Also see the "CookieLess" Session and Authenication options e.g.
http://msdn.microsoft.com/en-us/library/system.web.security.formsauthentication.formscookiepath.aspx If you are worried about cookies. This uses a URL session ID instead to track your session.
You can also use a SQL Server to track session state or a State server.
e.g.
<sessionState mode="SQLServer" sqlConnectionString="SQLSessionDB" cookieless="false" timeout="65" cookieName="MSESSID"/>
1A. SSL encrypts transport. Hence your cookies will be less likely to be stolen on route to the client or back. That doesn't mean a malicious program on the client computer can't steal it. This is very unlikely though.