防止具有相同站点 cookie 属性的 CSRF

Posted

技术标签:

【中文标题】防止具有相同站点 cookie 属性的 CSRF【英文标题】:Preventing CSRF with the same-site cookie attribute 【发布时间】:2016-12-21 15:26:35 【问题描述】:

我在网上冲浪,发现文章Preventing CSRF with the same-site cookie attribute。

在链接维护时,我们需要添加 Set-Cookie 标头。

设置-Cookie:键=值;仅http; SameSite=严格

现在我的问题是,我想在我的 ASP.NET 站点中设置所有 Cookie 和身份验证 Cookie。 我尝试使用 IIS 的标头来设置它,但有人说这是错误的实现方式。

下面我也试过了。

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

但这似乎对我没有帮助。

请建议我一个更好的方法来做到这一点。

谢谢。

【问题讨论】:

【参考方案1】:

在对HttpCookie Source 进行深入审查后,确认我们无法对代码执行此操作,因为无法在 Cookie 上添加额外属性,并且类被标记为密封。

但无论如何我还是通过如下修改 web.config 来管理解决方案。

<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>

这会在每个 Set-Cookie 上添加 SameSite=strict

【讨论】:

.NET 现已支持此功能,请在下方查看我的答案 从 Asp.NET 4.7.2 开始,您可以通过将以下行添加到 Web.config 中的 &lt;system.web&gt; 节点来执行相同的操作。 &lt;httpcookies samesite="Strict"/&gt; 我尝试在 .Net 4.7.2 中使用 但它不适用于 Asp.Net Identity cookie。这个重写规则做到了。 @AugustoBarreto Asp.Net Identity 忽略 .config 设置。解决方案是实现自己的 Cookie 处理程序。派生自 System.IdentityModel.Services.CookieHandler 并实现 WriteInternal 方法。 @L01NL 我的目标是 4.7.2 并且仍然得到 Unrecognized attribute 'samesite' 在 MS 文档中也没有提到【参考方案2】:

因为在这个时代,我们使用 owin 来修复同样愚蠢的 webapi cookie 错误...

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);
    

确保中间件在 .UseWebApi() 之前注册

【讨论】:

+1 这种方法效果很好。代码中有一个小错误——当您的登录页面设置多个 cookie 时,它​​会过滤掉 cookie。我修复了错误并完善了代码here。【参考方案3】:

您也可以在创建 cookie 时在代码中设置:

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

Response.SetCookie(httpCookie);

这将为您提供以下标题:

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

在将其推入框架之前有点破解。

【讨论】:

更好的解决方案!但是,在响应时,您只能读取 cookie,但不能对其进行修改...您必须创建一个新的。【参考方案4】:

.NET 4.7.2 现在内置支持SameSite 属性。HttpCookie 现在有一个名为SameSite 的属性。 查看来自 Microsoft 的更多信息 here。

不再需要通过配置文件破解它。

【讨论】:

以防万一它通过此线程帮助其他旅行者:将 .NET 4.7.2 添加到 Visual Studio 2017 from dotnet.microsoft.com/download/dotnet-framework 我不知道为什么,但我仍然看到警告说“不允许使用 'sameSite' 属性。” 我使用的是 4.7.2【参考方案5】:

在 4.7.2 之前,您只需将字符串附加到 cookie 路径即可。

FormsAuthentication.SetAuthCookie(username, false, FormsAuthentication.FormsCookiePath + "; SameSite=Lax");

【讨论】:

这是一个重复的答案 @Julian 不是真的。另一个答案提到了自定义 cookie,而不是内置的 Forms Auth 一个 在哪里添加这一行? 验证用户名/密码后在您的登录页面中。您有 2 个选项用于从此类设置身份验证 cookie - 另一个是 FormsAuthentication.RedirectFromLogin()。【参考方案6】:

只需添加我的答案即可系统化在此处和其他地方找到的所有信息。

1。在 4.7.2 及更高版本下保护自定义 cookie

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

2。保护表单身份验证 cookie

在 web.config 中

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

3。保护 ASP.NET 会话 cookie

在 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;

有趣的事实:即使您设置了&lt;httpCookies requireSSL="true" /&gt;,ASP.NET 会话 cookie由于某种原因仍然是不安全的

3(a)。更新 01.2020:.NET 4.8 会话 cookie 现在默认为“SameSite”

安装最新的 Windows 更新将使您的会话 cookie 默认为 Lax。你可以在这里控制它:

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

4。 &lt;httpCookies samesite=xxx&gt; 不存在?

添加&lt;httpCookies sameSite="Strict" /&gt; 就像在 web.config 上面的评论中建议的那样不起作用,我收到了错误。

无法识别的属性'samesite'

即使我的目标是 4.7.2。在多个项目和多台机器上测试,VS2019 也没有在智能感知中显示这一点,MS 文档也没有在任何地方提及。

【讨论】:

我正在使用旧版 .NET 4.5 应用程序并且遇到了困难。正如你所说,the Nov. 2019 security update 似乎强制所有内容为SameSite=Lax,虽然它说这种行为可以在web.config 中更改,但实际上它只在 4.7.2 及更高版本中受支持。接下来我要从接受的答案中尝试rewrite 我正在使用 4.7.2 并在错误列表“不允许使用 'sameSite' 属性”下收到警告。它允许我构建解决方案,但不确定此警告。 目前,如果未指定 Same-Site,大多数浏览器会自动将 cookie 增加到 Lax,因此如果有人想要相反的情况(将安全性降低回无),我已经制定了类似的解决方案 @987654322 @(根据上面的答案) 如何在.NET 4.6.2中实现解决方案? 感谢“ 不存在”。为什么人们会传播这样的虚假信息?【参考方案7】:

为了将 SameSite 定义为 ASP.NET_SessionId cookie,我必须在 system.web 部分下设置 web.config:

<sessionState cookieSameSite="Lax" />

【讨论】:

非常感谢。这对我有用。就像指出 对我不起作用。 @ManishPradhan:我发现了同样的事情。我将我们的应用升级到 4.8 以利用 &lt;httpCookies sameSite="Lax" /&gt;,但这似乎没有任何作用。【参考方案8】:

https://www.nuget.org/packages/Microsoft.Owin.Security.Cookies/4.1.0 现在支持 SameSite。

这是一个非常好的消息,因为这里的其他解决方案没有那么出色:

实现OwinMiddleware:效果很好,除了性能。这可能是特定于我们环境的东西,但该解决方案大约占我们 CPU 的 10%。

&lt;outboundRules&gt;: 应该可以开始工作了。但是到目前为止,我看到的所有解决方案以及我们测试过的解决方案,包括这个线程中的解决方案,当在同一个响应中设置多个 cookie 时都会出现一些问题。

【讨论】:

以上是关于防止具有相同站点 cookie 属性的 CSRF的主要内容,如果未能解决你的问题,请参考以下文章

SameSite Cookie,防止 CSRF 攻击

Cookie:SameSite,防止CSRF攻击

防止跨站攻击——CSRFToken

是否可以将相同站点属性添加到 Spring Security CSRF 的 .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFal

跨站点请求伪造(CSRF)

微信小程序和具有权限认证CSRF机制的Django服务端交流