如何在 ASP.NET 中将 SameSite cookie 属性减少回无?

dri*_*zin 4 asp.net csrf samesite

为了避免 CSRF(跨站点请求伪造),大多数浏览器(自 2019 年末以来)自动考虑任何未明确定义 SameSite 属性的 cookie 将被视为 Lax,而不是之前的默认值 None。

最近(2020 年 2 月,自 Chrome 80 起)浏览器也忽略了定义 SameSite=None 且不安全的 cookie。

如何在我的 Web.config 中更改我的会话 cookie 以自动更改为无(以保持我的 SSO 集成工作)?

dri*_*zin 9

2020 年 8 月 3 日编辑Chrome 85 不允许不安全的 SameSite=None cookie
我已相应更新代码:1) 仅SameSite=None当连接为 https时才适用;2) 仅适用于Secure;https 连接;3)SameSite=None如果是 http 并且属性添加了相同站点,则删除(重写规则)

原回复

这是一个纯 web.config 解决方案,它:

  • 定义会话 cookie 应该用 SameSite=None
  • 附加SameSite=None到任何未明确定义 SameSite 属性的 cookie(使用适用于所有框架版本的方法,在最坏的情况下,如果某些属性不被接受,您可以将其删除)
  • Secure将属性附加到任何尚不安全的 cookie(只要它是 https 请求)
  • SameSite=None如果它被以前的规则应用并且由于缺少 https 而无效,则将其删除
<!-- This sets ASP.NET_SessionId cookie to SameSite=None, 
avoiding the default of current frameworks which is LAX -->
<system.web>

<!-- in newer framework versions you have to change the samesite 
level like by changing this default level -->
<!-- in old versions these attributes might not be allowed
and in case (if they don't work) just ignore/skip them -->

<sessionState cookieSameSite="None" />
<httpCookies sameSite="None"/>
<authentication mode="Forms">
    <forms ..... cookieSameSite="None" />
</authentication>

...
</system.web>
...
<system.webServer>
<rewrite>
   <outboundRules>
    <!-- for old versions the only solution is to intercept/modify cookies -->

    <!-- Add "SameSite=None" to any cookie which does NOT have it yet -->
    <!-- currently this only works for secure https cookies -->
    <rule name="Add SameSite">
     <conditions>
      <add input="{RESPONSE_Set_Cookie}" pattern="." />
      <add input="{RESPONSE_Set_Cookie}" pattern="; SameSite=None" negate="true" />
      <add input="{HTTPS}" pattern="on" ignoreCase="true" />
     </conditions>
     <match serverVariable="RESPONSE_Set_Cookie" pattern=".*" negate="false" />
     <action type="Rewrite" value="{R:0}; SameSite=None" />
    </rule>

    <!-- Add "Secure" to any cookie which does NOT have it yet, as long as it's HTTPS request or else a secure cookie would just be ignored -->
    <rule name="Add Secure">
     <conditions>
        <add input="{RESPONSE_Set_Cookie}" pattern="." />
        <add input="{RESPONSE_Set_Cookie}" pattern="; Secure" negate="true" />
        <add input="{HTTPS}" pattern="on" ignoreCase="true" />
     </conditions>
     <match serverVariable="RESPONSE_Set_Cookie" pattern=".*" negate="false" />
     <action type="Rewrite" value="{R:0}; Secure" />
    </rule>

    <!-- If samesite was set to none by cookieSameSite="None", -->
    <!-- remove it for non-https requests (currently only works for https) -->
    <rule name="No SameSite For HTTP">
     <conditions>
      <add input="{HTTPS}" pattern="off" ignoreCase="true" />
     </conditions>
     <match serverVariable="RESPONSE_Set_Cookie" pattern="(.*);(\s*)SameSite=None" />
     <action type="Rewrite" value="{R:1}" />
    </rule>


   </outboundRules>
</rewrite>
</system.webServer>

Run Code Online (Sandbox Code Playgroud)

如果您不使用<sessionState cookieSameSite="None" />某些较新的 ASP.NET Framework 版本,则默认情况下会呈现SameSite=Lax. 如果您只是将重写规则添加SameSite=None到所有 cookie 中,您将获得两次 SameSite 属性,根据我的测试,该属性在 Chrome 和 Firefox 等某些浏览器中有效(将使用最后一次出现的 SameSite 属性)但不起作用在一些像 Edge(它使用属性的第一次出现)中。

由于这第一个标签<sessionState cookieSameSite="None" />会自动设置SameSite=None,但不会自动添加Secure属性,我已经配置SameSite=NoneSecure独立的规则。如果我将所有内容都放在一个规则中,我最终会得到重复的属性SameSite=None,这可能会破坏浏览器(如上所述,它是无效的,浏览器可能会不一致地处理此问题)。

Secure,如果它是HTTPS请求仅添加,所以如果你还在接受HTTP连接你的会话cookie不会有Secure增加,这将使浏览器会忽略您的Cookie(和会话都不会工作)。如果您使用负载均衡器或反向代理,则应使用HTTP_X_FORWARDED_PROTO 属性

最后,在某些版本的 Safari中存在一个错误,浏览器无法理解SameSite=None并将其视为SameSite=Strict. 因此,对于那些特定版本,您可能决定不 render SameSite=None,尽管如果未指定,默认值仍然是SameSite=Laxlevel ,这可能不是您需要的(尚未找到解决方案)。