Setting SameSite=None and Secure in ASP.NET - c#

Read about the SameSite changes enforced to prevent Cross-Site Forgery.
Source: https://blog.chromium.org/2019/10/developers-get-ready-for-new.html
I'm trying to set its value to "None" and use Secure as advertised.
My current web.config setting is as below:
<system.web>
<sessionState cookieless="UseCookies"
timeout="20"
cookieSameSite="None"
xdt:Transform="Replace"
xdt:Locator="Match(cookieless)"/>
</system.web>
Documentation Soure:
https://learn.microsoft.com/en-us/dotnet/api/system.web.configuration.sessionstatesection.cookiesamesite?view=netframework-4.8#System_Web_Configuration_SessionStateSection_CookieSameSite
But still I get the below error:
A cookie associated with a resource at `mywebsite.net` was set with `SameSite=None` but without `Secure`. A future release of Chrome will only deliver cookies marked `SameSite=None` if they are also marked `Secure`.
How do I specify secure attribute in the above web.config file ? Any leads will be much appreciated.

According to this link from Microsoft, sessionState doesn't have that attribute so it falls back to the httpCookies section.
https://learn.microsoft.com/en-us/aspnet/samesite/system-web-samesite
Hope that helps.

You can also set it per cookie creation
using SameSiteMode = Microsoft.AspNetCore.Http.SameSiteMode;
....
context.HttpContext.Response.Cookies.Append(cookie.Key, cookie.Value,
new CookieOptions { SameSite = SameSiteMode.None,Secure = true });

Related

Stop session from expiring when browser closes in MVC

I am facing a session issue After I close my browser my session expires, and after re-open browser, I have to log in again.
I don't want to expire my session on browser close.
I am using this in my web.config file:
<authentication>
<forms loginUrl="~/account/login" name="astroswamig" slidingExpiration="true" timeout="1000"></forms>
</authentication>
<sessionState mode="StateServer" cookieless="false" timeout="1000" />
and this in my controller:
string str = JsonConvert.SerializeObject(user);
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1, user.CustEmail, DateTime.Now, DateTime.Now.AddDays(120), true, str);
string enctryptTicket = FormsAuthentication.Encrypt(ticket);
HttpCookie authCustCookie = new HttpCookie(FormsAuthentication.FormsCookieName, enctryptTicket);
authCustCookie.Domain = "xyz.com";
Response.Cookies.Add(authCustCookie);
The web.config sample in the question is using StateServer mode, so the out-of-process ASP.NET State Service is storing state information. You will need to configure the State Service; see an example of how to do that in the "STATESERVER MODE(OUTPROC MODE)" section here:
https://www.c-sharpcorner.com/UploadFile/484ad3/session-state-in-Asp-Net/
Also be sure to read the disadvantages section of the above linked article to make sure this approach is acceptable for your needs.
Another way to manage user session is using the InProc mode to manage sessions via a worker process. You can then get and set HttpSessionState properties as shown here:
https://www.c-sharpcorner.com/UploadFile/3d39b4/inproc-session-state-mode-in-Asp-Net/
and also here:
https://learn.microsoft.com/en-us/dotnet/api/system.web.sessionstate.httpsessionstate?view=netframework-4.8#examples
Again be sure to note the pros and cons of InProc mode in the above linked article to determine what approach best fits your needs.

User.Identity.IsAuthenticated is always false

I am using Membership provider but how do I get my username and password to login/signin? When I check to see with this code:
if (User.Identity.IsAuthenticated)
// this code always returns false
I have this before when the user uses asp:Login to login:
if (Membership.ValidateUser(email, password))
{
// this is true but what am I missing here to make above not be false?
The so called duplicate question/answer uses SetAuthCookie which according to this (System.Web.HttpContext.Current.User.Identity.IsAuthenticated fails sometimes) causes issues and I need to avoid it.
Use code like below to make it work. The method RedirectFromLoginPage will create the authentication cookie as well as redirect the user to the original page or the default URL (i.e. home page) defined in web config.
if (Membership.ValidateUser(email, password))
{
// Log the user into the site
FormsAuthentication.RedirectFromLoginPage(email, false);
}
Also, make sure that forms authentication is enabled in web config. At a minimum at least set mode="Forms" if not other settings under authentication.
<authentication mode="Forms">
<forms loginUrl="member_login.aspx"
defaultUrl="index.aspx" />
</authentication>

HttpContext.Current.User.Identity.IsAuthenticated returns false

I have a strange issue.
I have a page with the following code.
if (!HttpContext.Current.User.Identity.IsAuthenticated)
{
Server.Transfer(#"~/Views/Public/Unauthorised.aspx");
return;
}
For some reason, with one user (and we've narrowed it down to his single machine and windows logon profile), IsAuthenticated always returns false. Even though he is logged into the website, and can navigate to other pages that require authenticated user. Except this one page.
We checked that the machine accepts all cookies and we still get the same issue. I'm not sure where to go from here... any suggestions?
There are at least two known cases that can make this behavior.
First case when you have set requireSSL="true" on the Authentication session on web.config and you call that function from a non secure page. So double check if the page is secure or not, if you use the requireSSL="true"
Debug.Assert(Request.IsSecureConnection, "The IsAuthenticated will fail.");
if (!HttpContext.Current.User.Identity.IsAuthenticated)
{
Server.Transfer(#"~/Views/Public/Unauthorised.aspx");
return;
}
Second case when you do not have set the domain="site.com" again on authentication session inside the web.config, and you try to request a cookie the one time from the www.yoursitename.com and the other from yoursitename.com. In that case the authentication cookies are different and it will fail. So set that parameter among others on web.config.
<authentication mode="Forms">
<forms domain="yoursitename.com" />
</authentication>

How to secure the ASP.NET_SessionId cookie?

I have set the .ASPXAUTH cookie to be https only but I am not sure how to effectively do the same with the ASP.NET_SessionId.
The entire site uses HTTPS so there is no need for the cookie to work with both http and https.
To add the ; secure suffix to the Set-Cookie http header I simply used the <httpCookies> element in the web.config:
<system.web>
<httpCookies httpOnlyCookies="true" requireSSL="true" />
</system.web>
IMHO much more handy than writing code as in the article of Anubhav Goyal.
See: http://msdn.microsoft.com/en-us/library/ms228262(v=vs.100).aspx
Here is a code snippet taken from a blog article written by Anubhav Goyal:
// this code will mark the forms authentication cookie and the
// session cookie as Secure.
if (Response.Cookies.Count > 0)
{
foreach (string s in Response.Cookies.AllKeys)
{
if (s == FormsAuthentication.FormsCookieName || "asp.net_sessionid".Equals(s, StringComparison.InvariantCultureIgnoreCase))
{
Response.Cookies[s].Secure = true;
}
}
}
Adding this to the EndRequest event handler in the global.asax should make this happen for all page calls.
Note: An edit was proposed to add a break; statement inside a successful "secure" assignment. I've rejected this edit based on the idea that it would only allow 1 of the cookies to be forced to secure and the second would be ignored. It is not inconceivable to add a counter or some other metric to determine that both have been secured and to break at that point.
Going with Marcel's solution above to secure Forms Authentication cookie you should also update "authentication" config element to use SSL
<authentication mode="Forms">
<forms ... requireSSL="true" />
</authentication>
Other wise authentication cookie will not be https
See: http://msdn.microsoft.com/en-us/library/vstudio/1d3t3c61(v=vs.100).aspx
Found that setting the secure property in Session_Start is sufficient, as recommended in MSDN blog "Securing Session ID: ASP/ASP.NET" with some augmentation.
protected void Session_Start(Object sender, EventArgs e)
{
SessionStateSection sessionState =
(SessionStateSection)ConfigurationManager.GetSection("system.web/sessionState");
string sidCookieName = sessionState.CookieName;
if (Request.Cookies[sidCookieName] != null)
{
HttpCookie sidCookie = Response.Cookies[sidCookieName];
sidCookie.Value = Session.SessionID;
sidCookie.HttpOnly = true;
sidCookie.Secure = true;
sidCookie.Path = "/";
}
}
It is also worth considering:
Using cookie prefixes
__Secure-, which signals to the browser that the Secure attribute is required.
__Host-, which signals to the browser that both the Path=/ and Secure attributes are required, and at the same time, that the Domain attribute must not be present.
A good article on why this helps
https://check-your-website.server-daten.de/prefix-cookies.html
Renaming your cookies
Instead of using names that clearly identify programming language.
e.g
ASP.NET_SessionId = __Secure-SID
Using samesite settings
sameSite="Lax"
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite
Make cookie https secure
requireSSL="true"
SECURE EXAMPLE
<sessionState cookieless="false" cookieName="__Secure-SID" cookieSameSite="Lax" />
<httpCookies httpOnlyCookies="true" sameSite="Lax" requireSSL="true" />
Adding onto #JoelEtherton's solution to fix a newly found security vulnerability. This vulnerability happens if users request HTTP and are redirected to HTTPS, but the sessionid cookie is set as secure on the first request to HTTP. That is now a security vulnerability, according to McAfee Secure.
This code will only secure cookies if request is using HTTPS. It will expire the sessionid cookie, if not HTTPS.
// this code will mark the forms authentication cookie and the
// session cookie as Secure.
if (Request.IsSecureConnection)
{
if (Response.Cookies.Count > 0)
{
foreach (string s in Response.Cookies.AllKeys)
{
if (s == FormsAuthentication.FormsCookieName || s.ToLower() == "asp.net_sessionid")
{
Response.Cookies[s].Secure = true;
}
}
}
}
else
{
//if not secure, then don't set session cookie
Response.Cookies["asp.net_sessionid"].Value = string.Empty;
Response.Cookies["asp.net_sessionid"].Expires = new DateTime(2018, 01, 01);
}
If the entire site uses HTTPS, your sessionId cookie is as secure as the HTTPS encryption at the very least. This is because cookies are sent as HTTP headers, and when using SSL, the HTTP headers are encrypted using the SSL when being transmitted.

AuthenticationSection.Mode returns Windows when web.config is set to Forms

So my Web.Config File has:
<authentication mode="Forms">
<forms loginUrl="~/Home/Index" timeout="2880" />
</authentication>
in my Application_Start() i make the following calls
Configuration configuration = WebConfigurationManager.OpenWebConfiguration(null);
AuthenticationSection authentication = (AuthenticationSection)configuration.GetSection("system.web/authentication");
AuthenticationType = authentication.Mode;
The problem is that AuthenticationType ends up being Windows no matter what the value i set in the web.config file. I need to pull this value to process the page differently depending on how it is configured and can't seem to get the right values.
I think passing null to parameter of OpenWebConfiguration is making it open the configuration file of the machine.
If you read the MSDN docs on this. You'll notice it says that passing null will give you the root web.config.
So you may think that's what you want. But it's not. The root web.config is actually in the .NET installation path....
usually c:\windows\Microsoft.NET\Framework[.NET VERSION]\Config
Try passing the path of the Configuration file. Use this statement in place of path to get current website path
WebConfigurationManager.OpenWebConfiguration(System.Web.Hosting.HostingEnvironment.ApplicationVirtualPath)
this makes it sure you get the right config file every time , in any environment
Or just use the static ConfigurationManager.GetSection method which will open the config.file for the running application the code is executed it.
var authentication = (AuthenticationSection)ConfigurationManager.GetSection("system.web/authentication");
AuthenticationType = authentication.Mode;
http://msdn.microsoft.com/en-us/library/system.configuration.configurationmanager.getsection.aspx
Retrieves a specified configuration section for the current application's default configuration.
May be it is referring wrong web.config. Here is something you might want to try:
Configuration webconfig = System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration("~");
System.Web.Configuration.SystemWebSectionGroup sysweb = (System.Web.Configuration.SystemWebSectionGroup)webconfig.GetSectionGroup("system.web");
System.Web.Configuration.AuthenticationSection authSection = sysweb.Authentication;
System.Web.Configuration.AuthenticationMode authmode = authSection.Mode;

Categories