Firefox does not accept ASP.NET authentication cookies - asp.net

I'm having this issue with Firefox browser when deploy our application to the QA environment. We have an ASP.NET 4 application with Form Authentication. In our application, we have 2 cookies: 1 for authentication ticket, another for other information.
The issue is: everytime I login to the system using Firefox, I'm bounced back to the login page.
When I use Fiddle to investigate the issue, I found out that for some reason Firefox doesn't "accept" our cookies: The 1st request to the Login page, our server returns the cookies just fine in the Headers:
Set-Cookie: .ASPXAUTH_Imp=...; expires=Thu, 07-Jun-2012 06:37:24 GMT; path=/
Set-Cookie: .ASPXAUTH=...; expires=Wed, 06-Jun-2012 09:57:24 GMT; path=/
However, in the next response, our cookies do not present in the request header.
This issue does not happen in any other browsers (IE, Chrome, etc). In other browsers, the cookies are accepted and passed along in the next requests.
When I view the cookies stored in Firefox, I can see my website, but it has only the ASP.NET_sessionID cookie. There's no trace of the other 2 cookies.
One more interesting point is this issue only happens in QA environment ( which has the LAN IP 10.16.x.x. I tried to use the machine name the the issue persists). When I debug in Visual Studio using localhost, it works perfectly fine.
This is my code for sending Cookie to client:
' ASP.NET authentication cookie '
Dim cookieExpiration As DateTime = DateTime.Now.AddMinutes(Constants.WebSettingsConst.TimeOut)
Dim authenticationTicket = New FormsAuthenticationTicket(2, CurrentContext.UserContextID(), DateTime.Now, cookieExpiration, True, String.Empty, FormsAuthentication.FormsCookiePath)
Dim encryptedTicket As String = FormsAuthentication.Encrypt(authenticationTicket)
Dim authCookie = New HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket)
authCookie.Expires = authenticationTicket.Expiration
authCookie.Path = FormsAuthentication.FormsCookiePath
'HttpContext.Current.Response.Cookies.Remove(FormsAuthentication.FormsCookieName)'
HttpContext.Current.Response.Cookies.Add(authCookie)

It sounds obvious, but have you checked the cookie settings in FireFox. If you go into privacy and pick use custom history you can specify not to accept cookies from third parties or only from specific sites.
I'm doing exactly the same as you and have no problems.
Dim authTicket As New FormsAuthenticationTicket(1, userIdentity, Date.Now, _
Date.Now.AddMinutes(15), False, userData)
Dim encTicket As String = FormsAuthentication.Encrypt(authTicket)
Dim faCookie As New HttpCookie(FormsAuthentication.FormsCookieName, encTicket)
Response.Cookies.Add(faCookie)

Related

What is the default timeout for Cookie in ASP.NET?

Cookie is a executable program, which the server posts to client machines but what is the timeout of the cookie
Learning the concept of cookies so this question comes to my mind.
For ASP.NET Core by default cookie set with Append(string, string) or Append(String, String, CookieOptions) with default options will result in so called session cookie which will expire once you log off or close the browser.
app.MapGet("/api/ttt", (HttpResponse resp) =>
{
resp.Cookies.Append("testcookie", "val");
resp.Cookies.Append("testcookie1", "val", new CookieOptions());
return new { Test = "ok" };
});
You can control the cookie expiration by setting MaxAge or Expires properties on CookieOptions.
Note that ASP.NET Core has several specific cookies (like auth cookies) which can have their own default lifetimes.

ASP.NET_SessionId not found in OWIN OpenIdConnectAuthentication

BackGround : User once logged in to the our Web Application (using App level credential) will be presented with with Mail System they want to use based on that user will be redirected to respective authorization server to authenticate (using login / password of their mail system) and the auth server will return an access token back.
In Notification events like OnAuthorizationCodeReceivedAsync or OnAuthenticationFailedAsync; we are not getting ASP.NET_SessionId so having said that i am not able to use any of the session values which are set before OAuth Flow.
Refer below Code for more details.
app.UseOpenIdConnectAuthentication(New OpenIdConnectAuthenticationOptions With {
.ClientId = appId,
.ClientSecret = appSecret,
.Authority = "https://login.microsoftonline.com/common/v2.0",
.Scope = $"openid email profile offline_access {ewsScopes}",
.RedirectUri = redirectUri,
.PostLogoutRedirectUri = redirectUri,
.TokenValidationParameters = New TokenValidationParameters With {
.ValidateIssuer = False
},
.Notifications = New OpenIdConnectAuthenticationNotifications With {
.AuthenticationFailed = AddressOf OnAuthenticationFailedAsync,
.AuthorizationCodeReceived = AddressOf OnAuthorizationCodeReceivedAsync
}
})
I am not able to get any session values in HttpConext.Current.Session which are set before OAuth flow in notification events.
As per below SO; i tried different approaches like SystemWebCookieManager, UseKentorOwinCookieSaver but issue not resolved.
ASP.NET_SessionId + OWIN Cookies do not send to browser
What could be the issue and how can I resolve it?
ByDefault; OpenIDConnect uses form post redirects which are incompatible with SameSite. Due to that Application Session cookie not sent over and that is how it should be.
As per couple of Stack overflow link below; using either URL rewrite or below web.config allows us to maintain session when response is posted back to Callback url but we still need to use Owin's SystemWebCookieManager for that in order to work.
Browser won't set ASP.NET_SessionId cookie on payment gateway's post request to our site
how SameSite attribute added to my Asp.net_SessionID cookie automatically?
Considering above scenario; for OpenIDConnect Authentication; setting samesite cookie to none and secure; that should work but i afraid that would raise CSRF (Cross site request Forgery) vulnerability for application.
Hence, An alternative is to switch to the Code response type which uses HTTP redirects and works with SameSite=Lax. Set the appropriate code response mode and response type.
ResponseMode = OpenIdConnectResponseMode.Query;
ResponseType = OpenIdConnectResponseType.Code;
https://github.com/aspnet/AspNetKatana/blob/635c92f641ad1e014eead31cc7a365004949fda5/src/Microsoft.Owin.Security.OpenIdConnect/OpenIdConnectAuthenticationOptions.cs#L65-L66

ASP.NET cross subdomain cookies not being attached to request

I've been trying to build a local proof of concept to move over our current solution to a different URL structure. I'm using ASP.NET with 3 projects that currently has these URLs mapped to them:
mysite.com
mysite.com/api
mysite.com/app
To setup the proof of concept I've setup 3 sites locally in IIS with the following URLs:
mysite.com
api.mysite.com
app.mysite.com
And have added the following entries into the HOSTS file:
127.0.0.1 mysite.com
127.0.0.1 app.mysite.com
127.0.0.1 api.mysite.com
Currently app.mysite.com talks to api.mysite.com to perform a user login, which returns a cookie back in the response. The issue is that the cookie is not being stored under mysite.com. Subsequent requests to api.mysite.com don't have the cookie attached in the request header, and therefore fail.
I've experimented setting the cookie's domain property with no success, as well as not including a domain property.
An example of a cookie returned in the request:
Set-Cookie: MyCookie=somestuff; domain=.mysite.com; expires=Sat, 06-Sep-2014 00:02:04 GMT; path=/; HttpOnly
Yet the cookie is never attached to any requests to api.mysite.com nor can i see it in the cookie browser of Chrome, Firefox, IE etc...
Note that I've enabled CORS in web.config to enable cross domain requests.
EDIT:
In response to Owain's answer. I'll clarify my current setup a little more.
Regarding <machineKey> I have created a machineKey and used the same values on both applications in the web.config file. This was already working locally and in production when using mysite.com/api and mysite.com/app It wasn't till moving to subdomains that i ran into this issue.
Here is my code for creating and attaching the cookie:
private void EncryptAndAttachCookieToHeaders(FormsAuthenticationTicket ticket)
{
string encryptedTicket = FormsAuthentication.Encrypt(ticket);
HttpCookie newCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);
newCookie.Domain = ".mysite.com";
newCookie.Expires = DateTime.Now.AddMonths(3);
newCookie.HttpOnly = true;
newCookie.Secure = false;
System.Web.HttpContext.Current.Response.Cookies.Add(newCookie);
// For testing purposes
HttpCookie hc = new HttpCookie("cookie1", "value");
hc.Domain = ".mysite.com";
hc.Expires = DateTime.Now.AddMonths(3);
HttpContext.Current.Response.Cookies.Add(hc);
HttpCookie hd = new HttpCookie("cookie2", "value");
hd.Domain = ".api.mysite.com";
hd.Expires = DateTime.Now.AddMonths(3);
HttpContext.Current.Response.Cookies.Add(hd);
All of these cookies (real one plus the two tests) are visible when viewing the response in Fiddler. However subsequent requests to api.mysite.com do NOT have any cookies attached in the request header. The browser doesn't seem to want to store the cookie now that I've moved to the subdomain structure.
To make cross domain login work you first need to edit the <machineKey> element inside the web.config.
By default it is something like this
<machineKey
validationKey="AutoGenerate,IsolateApps"
decryptionKey="AutoGenerate,IsolateApps"
validation="SHA1"
decryption="Auto" />
With these settings, the .NET framework uses the automatically generated validationKey and decrytionKey
With the default settings the validation key and the decryption key will get generated by ASP.NET and will get used for authentication ticket and cookie, if you want multiple applications to share the same authentication ticket and cookie, you just need to set the validationKey and decrytionKey in all the applications to the same values
Make sure they are the same in both application something like for example
<machineKey
validationKey="FBFF3D4EFD359FD58AA480E0A63A9C817463A30EF5AFF4E212AD3321C122AECFFEC427C26D24B67296F5EBBB6A3736BF37A5027718E5426B92C9AC606F9AD66F"
decryptionKey="048F8A9F3D6A7D2E88738B36BEEB85FF0B4E23EEF11976D1C0F6F03B91CCFC37"
validation="SHA1"
decryption="AES" />
You can easily create some keys on this site http://aspnetresources.com/tools/machineKey
To make the authentication cookie visible at all other sub domains, you'll need to modify the cookie’s domain attribute.
// Call SetAuthCookie method
FormsAuthentication.SetAuthCookie("Test account", false);
//modify the Domain attribute
System.Web.HttpCookie TestCookie =
System.Web.Security.FormsAuthentication.GetAuthCookie(User.Identity.Name.ToString(), false);
TestCookie.Domain = "mysite.com"; // (Also try ".mysite.com" i'm unsure about this one) the second level domain name
Response.AppendCookie(TestCookie);
This should be everything you need to make cross domain cookies work
I found out the answer. The issue actually resided in how the AJAX request was being formed. I had to add an AJAX property called withCredentials to allow the browser to send the cross domain cookie. A drawback to this approach is that IE 9 and older don't support it....
From post Setting a cookie on a subdomain from an ajax request :
Set the allow Credentials header on api
Access-Control-Allow-Credentials: true
Use withCredentials for the request
$.ajax({
url: a_cross_domain_url,
xhrFields: {
withCredentials: true
}
});
Otherwise the XMLHttpRequest will not send the cookies, regardless of the Access-Control-Allow-Credentials header.
Remove the wildcard on Access-Control-Allow-Origin
Access-Control-Allow-Origin: http://www.example.com
The wildcard * will not work. The browser will discard the response if withCredentials was set.

How come one web site can pickup cookies from another web site

I noticed something funny while using Fiddler to debug a cookie issue we are having. If the cookie path value is just the beginning of another site’s path value then the second site sees the first site’s cookies.
This is easier to show than to describe.
I created a simple site with the following ASPX code
<div>
Cookie Value <asp:Label ID="lblTest" runat="server"></asp:Label><br />
See Foo <asp:Label ID="lblSeeFoo" runat="server"></asp:Label><br />
See Foobar <asp:Label ID="lblSeeFoobar" runat="server"></asp:Label><br />
See Foonot <asp:Label ID="lblSeeFoonot" runat="server"></asp:Label>
</div>
In the code behind I create a cookie with a path based on ApplicationPath. The created cookie name includes the ApplicationPath name to make it easy to see in Fiddler. This code also looks for cookies from three specific web sites.
Protected Sub Page_Load(sender As Object, e As EventArgs) Handles Me.Load
Dim CookieName As String = "Test " + Me.Request.ApplicationPath.Replace("/"c, "")
Dim myCookie As HttpCookie = Me.Request.Cookies(CookieName)
If (myCookie Is Nothing) Then
myCookie = New HttpCookie(CookieName)
myCookie.Path = Me.Request.ApplicationPath
myCookie.Expires = DateTime.Now.AddDays(1)
myCookie.Value = DateTime.Now.ToString()
Response.Cookies.Add(myCookie)
End If
Me.lblTest.Text = myCookie.Value
Dim TestCookie As HttpCookie
TestCookie = Me.Request.Cookies("Test Foobar")
Me.lblSeeFoobar.Text = CStr(TestCookie IsNot Nothing)
TestCookie = Me.Request.Cookies("Test Foonot")
Me.lblSeeFoonot.Text = CStr(TestCookie IsNot Nothing)
TestCookie = Me.Request.Cookies("Test Foo")
Me.lblSeeFoo.Text = CStr(TestCookie IsNot Nothing)
End Sub
This application is then published to three web sites named Foo, Foobar and Foonot.
Viewing each site shows that Foobar and Foonot can see the cookie for Foo.
Here is Foobar’s result
Cookie Value 7/3/2014 10:40:01 AM
See Foo True
See Foobar True
See Foonot False
Foobar can read Foo’s cookies. Foonot can also see Foo's cookies. Foonot and Foobar do not see each other's cookies.
Here is the raw header information from Fiddler:
GET /Foobar/ HTTP/1.1
Accept: application/x-ms-application, image/jpeg, application/xaml+xml, image/gif, image/pjpeg, application/x-ms-xbap, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*
Accept-Language: en-US
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; InfoPath.3)
Accept-Encoding: gzip, deflate
Connection: Keep-Alive
Host: webdev
Cookie: Test Foobar=7/3/2014 10:40:01 AM; Test Foo=7/3/2014 10:39:43 AM
I tried searching for information on this issue but couldn’t come up with anything.
Is this a known thing?
Is there a way to prevent this?
Isn’t this a big security issue? In a shared hosting environment couldn’t I create a domain name that is longer that an existing one and pickup their cookies?
I'm not sure what the actual URL of Foo, Foobar and Foonot.
However, a cookie can be shared among multiple subdomains.
For example, IE10 shares the cookie among the following sites -
mysite.com
Foo.mysite.com
Foobar.mysite.com
Foono.mysite.com
If you want cookie to be available in the specific domain only, you can set the cookie's Domain property.
myCookie.Domain = "Foo.mysite.com";
When determining if a cookie is included in the request the cookie path is not examined as a ‘path’ but simply as a string value.
If it was processed as a path then the fact that one site happens to begin with the same text as another would not result in a match. MyDomain.com/Foo is a different web site than MyDomain.com/Foobar. I see it as a different site, IIS serves it up as a different web site, but the browser sees them as the same path as far as the cookies are concerned. The browser is simply doing a string compare on the path values and “/Foo” is the beginning of “/Foobar” so the browser includes those cookies.
Normally this is used so the cookies for a parent web site are available to the child we sites. If there is a site named “Parent” and a nested site named “Child” then the parent’s cookies with a path of “/Parent” would be available to the child site. The child’s cookies with a path of “/Parent/Child” would not be available to the parent. The situation I came across is that a site can pick up the cookies for one if its siblings when the sibling’s path is the start of that site’s path.
I suspect that this string comparison is the one that causes the cookie paths to be case sensitive.
So the answers to my questions are:
Is this a known thing?
Yes. The browser is doing a simple string comparison on the cookie’s path to determine if it should include the cookie in the request.
Is there a way to prevent this?
Yes. Append a slash to the end of the path. “/Foo/” is no longer a subset of “/Foobar/”
myCookie.Path = Me.Request.ApplicationPath + "/"
Isn’t this a big security issue? In a shared hosting environment couldn’t I create a domain name that is longer that an existing one and pickup their cookies?
No. As #the_lotus points out, the domains would be different. The paths only have an effect within a domain. I was only thinking of the paths and didn’t consider the domains.

Get current request's credentials for using in WebRequest

When accessing my site, the user has to enter his credentials. They are basically plain directory access credentials.
At a certain point I check if a certain file they want to download exists by calling
WebRequest req = HttpWebRequest.Create(checkUri.AbsoluteUri);
WebResponse res = req.GetResponse();
Although I can access the checkUri from the browser, I get a 401 when doing the above check. I think I have to set the
req.Credentials
But I don't know where the current credentials are stored...
Any ideas?
--Update--
Integrated Windows Authentication: No
Allow Anonymous: Off
Caler: Link on page of same site (GET)
Impersonation: default is off (don't even know how to enable it in asp.net mvc)
I was having a similar problem on a site where I'm using forms authentication, I was able to solve this problem by using the code provided here as the second reply in the thread.
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(uri);
// Add the current authentication cookie to the request
HttpCookie cookie = HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName];
Cookie authenticationCookie = new Cookie(
FormsAuthentication.FormsCookieName,
cookie.Value,
cookie.Path,
HttpContext.Current.Request.Url.Authority);
req.CookieContainer = new CookieContainer();
req.CookieContainer.Add(authenticationCookie);
WebResponse res = req.GetResponse();
I think you want this:
req.Credentials = CredentialCache.DefaultCredentials;
You're going to need to enable Integrated Windows Authentication.
I don't know what happens in ASP.NET MVC, but in ASP.NET Web Forms impersonation is turned on by:
<identity impersonate="true">
in web.config.

Resources