Preventing CSRF with the same-site cookie attribute
Asked Answered
R

8

51

I was surfing the web and found article Preventing CSRF with the same-site cookie attribute.

As on link maintain We need to add Set-Cookie header.

Set-Cookie: key=value; HttpOnly; SameSite=strict

Now My Question is, I want to set this in my ASP.NET site in all Cookies and Authentication Cookie. I tried to set this using header from IIS but someone says this is wrong way implementation.

I have also tried below.

HttpCookie newAuthenticationCookie = new HttpCookie(FormsAuthentication.FormsCookieName
                    , FormsAuthentication.Encrypt(newAuthenticationTicket))
                {
                    HttpOnly = true
                };
newAuthenticationCookie.Values.Add("SameSite", "strict");

But it seems like not helping me.

Please suggest me a better way to do this.

Thanks.

Rossini answered 15/8, 2016 at 12:10 Comment(0)
R
60

After Deep review on HttpCookie Source it's confirm that we cannot do this with the code, as there is no way to add extra attribute on Cookie and class is marked as sealed.

But still anyhow I manage solution by modifying web.config as below.

<rewrite>
  <outboundRules>
    <rule name="Add SameSite" preCondition="No SameSite">
      <match serverVariable="RESPONSE_Set_Cookie" pattern=".*" negate="false" />
      <action type="Rewrite" value="{R:0}; SameSite=strict" />
      <conditions>
      </conditions>
    </rule>
    <preConditions>
      <preCondition name="No SameSite">
        <add input="{RESPONSE_Set_Cookie}" pattern="." />
        <add input="{RESPONSE_Set_Cookie}" pattern="; SameSite=strict" negate="true" />
      </preCondition>
    </preConditions>
  </outboundRules>
</rewrite>

This add SameSite=strict on each Set-Cookie.

Rossini answered 15/8, 2016 at 14:35 Comment(14)
.NET has now support for this, check my answer belowIfill
Since Asp.NET 4.7.2 you can do the same thing by adding the following line to the <system.web> node in the Web.config. <httpcookies samesite="Strict"/>Pulverize
That's great v4.7.2 supports same site functionality, however that's a perfect world situation. Not everyone can upgrade an entire application(s) to the latest version of .NET without spending days, weeks or months making the leap to the latest version when dealing with enterprise size projects.Ingrid
I tried with <httpCookies sameSite="Strict" /> in .Net 4.7.2 but it did not work for the Asp.Net Identity cookie. This rewrite rule did.Dilatation
@AugustoBarreto Asp.Net Identity ignore the .config settings. Solution is to implement your own Cookie Handler. Derive from System.IdentityModel.Services.CookieHandler and implement WriteInternal method.Supplication
lets say i have two urls, a.abc.com and b.abc.com, both pointing to same site. this rule works when i access a.abc.com, where was when i try b.abc.com, it is giving anti-forgery token error. any suggestions?Allout
@Pulverize I'm targeting 4.7.2 and still get Unrecognized attribute 'samesite' also not mentioned in MS docsMilena
For reference, this is in the MS docs at learn.microsoft.com/en-us/dotnet/api/…Guardianship
This added the samesite attribute but it did not remove a default value for the attribute. there was there for two values for samesite. I used <sessionState cookieSameSite="None" /> instead and it removed the other value.Foxglove
@Alex and for reference, the system.web config XML is case sensitive and camel cased, e.g. <httpCookies requireSSL="false" sameSite="Strict" />. I tried this in .NET Franework 4.8.03752 and it set the SameSite cookie attribute on all cookies except for the ASP.NET_SessionId cookie.Experimentalism
This fix worked for me in all browsers apart from IE? anyone else seeing this?Himself
These docs spell out which tags have which attributes -- some support requireSSL, some support sameSite, and some support both.Bugloss
this seems to be the easiest pre 4.7.2 solutionCertified
@Shad yes, check my answer below: https://mcmap.net/q/119068/-preventing-csrf-with-the-same-site-cookie-attributeMilena
E
34

You can also set this in code when creating a cookie:

var httpCookie = new HttpCookie("mycookie", "myvalue");
httpCookie.Path += ";SameSite=Strict";

Response.SetCookie(httpCookie);

This will give you the following header:

Set-Cookie:mycookie=myvalue; path=/;SameSite=Strict

bit of a hack until it's pushed in to the framework.

Emersion answered 16/2, 2018 at 15:7 Comment(1)
better solution! but, on Response you can only read cookie but you CAN T modified it...you have to create a new one.Quinta
M
29

Just adding my answer to systematize all the info found here and in other places.

1. To secure custom cookies under 4.7.2 and later

var c = new HttpCookie("test");
c.SameSite = SameSiteMode.Lax;

2. To secure Forms authentication cookie

In web.config

<authentication mode="Forms">
    <forms ..... cookieSameSite="Lax" />
</authentication>

3. To secure ASP.NET Session cookie

In Global.asax

void Session_Start(Object sender, EventArgs e)
{
    Response.Cookies["ASP.NET_SessionId"].SameSite = SameSiteMode.Lax;
    //while we're at it lets also make it secure
    if (Request.IsSecureConnection)
        Response.Cookies["ASP.NET_SessionId"].Secure = true;
}

Fun fact: even if you set <httpCookies requireSSL="true" /> the ASP.NET session cookie will still be non-secure for some reason.

3(a). UPDATE 01.2020: .NET 4.8 Session cookie is now "SameSite" by default

Installing the latest Windows Update will make your session cookies Lax by default. You can control it here:

<sessionState cookieSameSite="Lax" /> <!-- in system.web -->

4. <httpCookies samesite=xxx> does not exist?

Adding <httpCookies sameSite="Strict" /> like suggested in the comment above in web.config didn't work, I was getting the error.

Unrecognized attribute 'samesite'

Even though I'm targeting 4.7.2. Tested on multiple project and multiple machines, also VS2019 does not show this in intellisense and MS docs do not mention it anywhere.

Milena answered 8/9, 2019 at 8:23 Comment(5)
I'm working with a legacy .NET 4.5 application and having a hard time. It looks like the Nov. 2019 security update forced everything to be SameSite=Lax as you say, and while it says this behavior can be changed in web.config, it's only actually supported in 4.7.2 and above. I'm going to try rewrite from the accepted answer next.Bugloss
I am using 4.7.2 and getting warning under error list "The 'sameSite' attribute is not allowed.". It allows me to build the solution but not sure about this warning.Armandarmanda
Currently most browsers are automatically increasing cookies to Lax if Same-Site is not specified, so in case someone wants the opposite (reduce the security back to None), I've made a similar solution here (based on the answer above)Shunt
How to implement the solution within .NET 4.6.2?Lymphosarcoma
Thanks for "<httpCookies samesite=xxx> does not exist". Why do people spread false informations like that?Geniagenial
I
18

.NET 4.7.2 has now built-in support for SameSite property.
The HttpCookie has now a property called SameSite.
See more info here from Microsoft.

No need anymore to hack this through the config file.

Ifill answered 24/5, 2018 at 11:24 Comment(3)
Just in case it helps another traveler through this thread: add .NET 4.7.2 to Visual Studio 2017 from dotnet.microsoft.com/download/dotnet-frameworkSwallow
I don't know why but I am still seeing the warning which says "The 'sameSite' attribute is not allowed."Armandarmanda
and I am using 4.7.2Armandarmanda
G
14

In order to have SameSite defined to ASP.NET_SessionId cookie I had to set the web.config under system.web section:

<sessionState cookieSameSite="Lax" />
Global answered 18/10, 2019 at 14:42 Comment(2)
Thanks a lot. This worked for me. Just like to point out <httpCookies sameSite="None/Strict/Lax" /> did not work for me.Telamon
@ManishPradhan: I found the same thing. I upgraded our app to 4.8 to take advantage of <httpCookies sameSite="Lax" />, but that didn't seem to do anything.Cammi
S
9

Because in this day and age we use owin to fix the same silly webapi cookie bug...

public class CookieSameSiteMiddleware : OwinMiddleware
{
    public CookieSameSiteMiddleware(OwinMiddleware next) : base(next)
    {
    }

    public override async Task Invoke(IOwinContext context)
    {
        var url = context.Request.Path.Value.ToLowerInvariant();

        if (url.Contains("/api/mylogin"))
        {
            context.Response.OnSendingHeaders(x =>
            {
                var scv = context.Response.Headers.FirstOrDefault(h => h.Key == "Set-Cookie");
                if (!scv.Equals(default(KeyValuePair<string, string[]>)))
                {
                    //context.Response.Headers.Remove("Set-Cookie");
                    context.Response.Headers.Set("Set-Cookie", scv.Value[0] + "; SameSite=strict");
                }

            }, null);
        }

        await this.Next.Invoke(context);
    }
}

Make sure the middle-ware is registered before .UseWebApi()

Spirochete answered 14/7, 2017 at 20:16 Comment(1)
+1 This approach worked well. There's a small bug in the code—it filters out cookies when your login page sets more than one cookie. I fixed the bug and polished up the code here.Aretta
L
4

Pre 4.7.2 you can just append the string to the cookie path.

FormsAuthentication.SetAuthCookie(username, false, FormsAuthentication.FormsCookiePath + "; SameSite=Lax");
Learnt answered 12/9, 2018 at 16:39 Comment(4)
this is a duplicate answerExceptive
@Exceptive not really. The other answer mentions custom cookies, not the built-in Forms Auth oneMilena
where to add this line?Verbalize
In your login page after you validate username/password. You have 2 options for setting the auth cookie from this class -- the other is FormsAuthentication.RedirectFromLogin().Learnt
F
0

https://www.nuget.org/packages/Microsoft.Owin.Security.Cookies/4.1.0 now supports SameSite.

That is very good news because the other solutions here doesn't work that brilliantly:

Implementing OwinMiddleware: Works great, except for performance. This might be something specific for our environment but that solution was about 10% of our CPU.

<outboundRules>: Probably possible to get working. But all solutions I've seen so far and we tested, including the one in this thread, had some issues when multiple cookies where set in the same response.

Fredfreda answered 8/1, 2020 at 22:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.