ASP.Net Cannot set cookie with SameSite=None - asp.net

I'm using MVC5 on IIS with .NET Framework 4.8.
I have the latest quality rollup installed(1) which is supposed to resolve some issues with samesite cookies.
I create three cookies as follows:
var now = DateTime.Now.ToLongTimeString();
var expiry = now.AddSeconds(30);
var cookieSameSiteNone = new HttpCookie("My.SameSite.None", $"sameSite None [{now}]")
{
Secure = true,
SameSite = SameSiteMode.None,
Expires = expiry
};
var cookieSameSiteLax = new HttpCookie("My.SameSite.Lax", $"sameSite Lax [{now}]")
{
Secure = true,
SameSite = SameSiteMode.Lax,
Expires = expiry
};
var cookieSameSiteStrict = new HttpCookie("My.SameSite.Strict", $"sameSite Strict [{now}]")
{
Secure = true,
SameSite = SameSiteMode.Strict,
Expires = expiry
};
Response.Cookies.Add(cookieSameSiteStrict);
Response.Cookies.Add(cookieSameSiteLax);
Response.Cookies.Add(cookieSameSiteNone);
These cookies are set in the Application_EndRequest of the Global.asax. The application also uses OWIN for authentication.
Using FireFox (v72.0.2) I get the following cookies:
Note the cookie where SameSite was set to None has been received as "Unset"
Any idea how to set a cookie with SameSite=None?
I have seen other SO questions that suggest applyin patches to the .NET Framework(2), but I already have these installed
(1) https://support.microsoft.com/en-gb/help/4534132/kb4534132-cumulative-update-for-net-framework
(2) How to set SameSite cookie attribute to explicit None ASP NET Core

This may be an issue with FireFox's display of Cookies. Chrome does not appear to suffer with the same problem.
I've logged a bug with Mozilla(1).
(1) https://bugzilla.mozilla.org/show_bug.cgi?id=1613622

Related

Asp.Net Core - Prevent Session cookie conflict between same domain applications

I'm using ASP.Net Core 2.2.
By default, session cookie is stored in a cookie named .AspNetCore.Session on a specific domain (e.g: mydomain.com).
In my case I have multiple .net core applications under the domain. mydomain.com/Module1, mydomain.com/Module2, etc...
With this scenario, all the applications share the same cookie for their session. The consequence is that an application try to read the session of the other and generate a warning in the logs:
Error unprotecting the session cookie.
System.Security.Cryptography.CryptographicException: The key {...} was not found in the key ring.
Although It's just a warning and session seems to working fine on each application, I wanted to know the proper way to handle this situation.
Thx.
A solution that I've found is to change the session cookie name for each application:
In Startup / Configure() :
app.UseSession(new SessionOptions() { Cookie = new CookieBuilder() {
Name = ".AspNetCore.Session.MyApp1"}});
When you have .AddAuthentication defined in Startup / ConfigureServices(), to fix this add cookie options this way. Worked for my case.
services.AddAuthentication(CookieScheme) // Sets the default scheme to cookies
.AddCookie(CookieScheme, options =>
{
options.LogoutPath = "/logout";
options.LoginPath = "/login";
options.Cookie = new CookieBuilder()
{
IsEssential = true,
SameSite = SameSiteMode.Lax,
SecurePolicy = CookieSecurePolicy.SameAsRequest,
Name = ".AspNetCore.Session.yourAppName"
};
});

ASP.NET Core AntiforgeryToken cookie is set to 1969 as expiration time

I have setup an authentication using simply cookies. Somehow I saw in Application tab of Chrome that antiforgery token cookie expiration time is set to 1969, 31st December.
In ConfigureServices I have:
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie(opts =>
{
var ts = TimeSpan.FromMinutes(30);
opts.Cookie.HttpOnly = true;
opts.Cookie.Expiration = ts;
opts.Cookie.SecurePolicy = CookieSecurePolicy.SameAsRequest;
opts.LoginPath = new PathString("/User/Authenticate");
opts.ExpireTimeSpan = ts;
opts.Cookie.MaxAge = ts;
opts.Validate();
});
and in Configure
app.UseCookiePolicy();
app.UseAuthentication();
Does it is a security concern ? Can that token be bypassed ? I didn't find any article related to antiforgery token default expiration date.
Setting the date of a cookie to a time in the past (or minimum time) is a very common technique of telling the browser to delete a cookie. You should not be concerned.

ASP.Net External Cookie with Sliding Expiration appearing as a Session cookie

I am trying to configure a sliding expiration cookie in Asp.Net. I am expecting the cookie to appear in the Google Chrome developer tools cookie manager with an expiration date 5 minutes after authentication, but it shows as "Session" and never expires until the sign-out button is clicked. It does go away if the browser is closed.
Below is the code as it currently stands. The website uses Saml based Single-Sign-On authentication with Kentor.AuthServices nuget package (now known as SustainSys.Saml2, we are behind in versions).
app.CreatePerOwinContext(ApplicationDbContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/signin"),
CookieSecure = CookieSecureOption.SameAsRequest,
ExpireTimeSpan = TimeSpan.FromMinutes(5),
SlidingExpiration = true,
Provider = new CookieAuthenticationProvider
{
OnApplyRedirect = ctx => { },
OnResponseSignIn = context =>
{
context.Properties.AllowRefresh = true;
context.Properties.ExpiresUtc = DateTimeOffset.UtcNow.AddMinutes(5);
}
}
});
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
Kentor.AuthServices.Configuration.Options.GlobalEnableSha256XmlSignatures();
The OnResponseSignIn block was recently added based on this MSDN answer:
https://forums.asp.net/t/2121970.aspx?OWIN+Authentication+ExpireTimeSpan+not+working
I want the cookies to expire in a 30-minute inactive period. The above code is set to 5 for ease of testing.
The developer tools show the cookie expiration time. This is not directly related to the authentication token expiration time, which should in fact be correct for your code too.
As indicated by this comment "The expiration information is stored in the protected cookie ticket". The token expiration time should take effect properly, even if you cannot see it in the developer tools as it's encrypted inside the cookie itself.

Forms authentication and authentication ticket cookie domain

I'm trying to configure DEV environment to support sub-domains with sharing authentication and session between them.
Currently, I configured IIS and hosts file on DEV machine to handle requests for mydomain, sd1.mydomain, sd2.mydomain, sd3.mydomain. Web application itself working as expected, I can browse all pages on all sub-domains, except the pages that requires authentication. When I try to log in, everything looks perfect on server side (user found, cookie created and added to response), but the cookie not arrives to browser (I tried Chrome and IE).
I have a code that creates and stores authentication ticket and I set domain=".mydomain" in authentication.forms in web.config:
var now = DateTime.UtcNow.ToLocalTime();
var ticket = new FormsAuthenticationTicket(
1 /*version*/, _user.Username, now, now.Add(FormsAuthentication.Timeout),
isPersistentCookie, _user.Username, FormsAuthentication.FormsCookiePath);
var encryptedTicket = FormsAuthentication.Encrypt(ticket);
var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);
cookie.HttpOnly = true;
if (ticket.IsPersistent)
{
cookie.Expires = ticket.Expiration;
}
cookie.Secure = FormsAuthentication.RequireSSL;
cookie.Path = FormsAuthentication.FormsCookiePath;
if (FormsAuthentication.CookieDomain != null)
{
cookie.Domain = FormsAuthentication.CookieDomain;
}
_httpContext.Response.Cookies.Add(cookie);
When I debug, the code above works fine, the user is correct and cookie with correct domain is added to response.
If I remove domain=".mydomain" from web.config, authentication works, but only on mydomain and not on sub-domains.
What I'm doing wrong?
Remove the dot on the beginning, from the domain=, you must have it as domain=".mydomain.com" with the first dot as stated here http://www.w3.org/Protocols/rfc2109/rfc2109 (page 7), thanks for the comment of #AlbatrossCafe
This setting is both on cookie and on authentication.
Nothing wrong. If the domain is not provided on a cookie, the cookie is supposed to work only for issuing domain.

Why did ASP.NET generate the same cookie key for a domain and subdomain?

Bug:
I've got an ASP.NET web application that occasionally sets identical cookie keys for ".www.mydomain.com" and "www.mydomain.com". I'm trying to figure out what default cookie domain ASP.NET sets, and how I accidentally coded the site to sometimes prepend a "." to the cookie domain.
When 2 cookies have the same key and are sent up from the browser, the ASP.NET web application is unable to differentiate between the two because the domain value is not sent in the header. (See my previous question)
Evidence:
I've enabled W3C logging on the web server and verified that both cookies are sent from the client. Here's an example from the log file (paired down for brevity).
80 GET /default.aspx page= 200 0 0 - - - - - +MyCookie2=sessionID=559ddb9b-0f38-4878-bb07-834c2ca9caae;+MyCookie2=sessionID=e13d83cd-eac2-46fc-b39d-01826b91cb2c;
Possible Factor:
I am using subdomain enabled forms authentication.
Here's my web.config settings:
<authentication mode="Forms">
<forms domain="mydomain.com" enableCrossAppRedirects="true" loginUrl="/login" requireSSL="false" timeout="5259600" />
</authentication>
Here's and example of setting custom cookies:
HttpCookie cookie1 = new HttpCookie("MyCookie1") {HttpOnly = true, Expires = expiration};
logosCookie["email"] = user.Email;
logosCookie["keycode"] = user.PasswordHash;
logosCookie["version"] = currentCookieVersion;
context.Response.Cookies.Remove("cookie1");
context.Response.Cookies.Add(cookie1);
// set FormsAuth cookie manually so we can add the UserId to the ticket UserData
var userData = "UserId=" + user.UserID;
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(2, user.Email, now, expiration, true, userData);
string str = FormsAuthentication.Encrypt(ticket);
HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, str)
{
HttpOnly = true,
Path = FormsAuthentication.FormsCookiePath,
Secure = FormsAuthentication.RequireSSL,
Expires = ticket.Expiration
};
if (FormsAuthentication.CookieDomain != null)
{
cookie.Domain = FormsAuthentication.CookieDomain;
}
context.Response.Cookies.Remove(FormsAuthentication.FormsCookieName);
context.Response.Cookies.Add(cookie1 );
Here's another example of setting a cookie.
var cookie2 = new HttpCookie("MyCookie2");
cookie2[CookieSessionIdKey] = Guid.NewGuid();
cookie2.Expires = DateTime.Now.AddYears(10);
HttpContext.Current.Response.Cookies.Set(cookie2);
Undesirable Resolution:
I can manually force the cookie domain to be a specific value, but I'd like to avoid explicitly declaring the domain. I'd prefer to use the default framework behavior and change my use of ASP.NET to avoid prepend the "." to the cookie domain for custom cookies.
When no domain is explicitly set by the server on the response, the browser is free to assign the cookie domain value. I haven't figured out exactly what conditions result in the browser setting "www.mydomain.com" vs ".mydomain.com" on a cookie domain when no domain is provided on the response, but it happened.
I have a feeling it's a result of explicitly setting the .ASPAUTH cookie domain value to ".mydomain.com" to enable cross subdomain authentication, while leaving other custom cookie domains set to the default (empty string, or "").
I'm going to go with the undesired solution, and explicitly set the cookie domain for all custom cookies to avoid browser quirks.

Resources