浏览器不会在支付网关向我们网站的发布请求上设置 ASP.NET_SessionId cookie

E. *_*gür 15 asp.net cookies session

我们在 Web 应用程序的支付过程中遇到了一个奇怪的问题,导致会话数据丢失。

在这个过程中,在我们的结帐页面用户被重定向到支付提供商的页面后,只要他/她在那里完成,就会被重定向回我们的网站(到我们指定的网址)。最后一个重定向是通过浏览器对支付提供商的 html 代码的评估完成的,该代码基本上由一个发布到我们网站的表单和几行在页面加载时发布该表单的 javascript 代码组成。此时浏览器发出 post 请求,但没有设置“ASP.NET_SessionId”cookie,该 cookie 存在于先前对完全相同的域(我们的应用程序的域)发出的请求中。更奇怪的是,它设置了我们使用的另一个名为“AcceptCookie”的 cookie。它只是简单地选择删除“ASP.NET_SessionId”cookie。

为了说明这种情况,我截取了一些屏幕截图。(在这些屏幕截图中,橙色和绿色矩形包含完全相同的值。)

  1. 这是当用户按下“签出”按钮时(向我们的应用程序)发出的请求。在此请求之后,用户被重定向到支付提供商的页面。

退房要求

  1. 这是用户在那里完成后由支付提供商提供的最后一页。如您所见,它只是一个简单的表单,会在页面加载时自动发布到我们的域中。

支付提供商的最终回应

  1. 但是这个发布请求不包括“ASP.NET_SessionId”cookie,这会导致获取新的会话 ID 和丢失以前的会话数据。同样,只缺少“ASP.NET_SessionId”,而不是另一个名为“AcceptCookie”的。

将用户带回我们网站的发布请求(在上一步中使用 javascript 制作)

最后我们认为在旧版本的浏览器上不会出现这个问题。在 Firefox 52 上它就像一个魅力,但在 Firefox 71 上会发生上述问题。

有任何想法吗?

注意:这是一个 ASP.NET MVC 应用程序,其 targetFramework="4.5.2"

祝你今天过得愉快。

E. *_*gür 21

我们想通了。

不知何故,“ASP.NET_SessionId”cookie 的“SameSite”属性默认为“Lax”,这会导致会话 cookie 没有被添加到支付网关的 javascript 代码发出的请求中。

我们在 web.config 文件中添加了以下规则以覆盖此值并将其设置为“无”。

<configuration>
  <system.webServer>
    <rewrite>
      <outboundRules>
        <rule name="Add SameSite" preCondition="No SameSite">
          <match serverVariable="RESPONSE_Set_Cookie" pattern=".*" negate="false" />
          <action type="Rewrite" value="{R:0}; SameSite=None" />
          <conditions>
          </conditions>
        </rule>
        <preConditions>
          <preCondition name="No SameSite">
            <add input="{RESPONSE_Set_Cookie}" pattern="." />
            <add input="{RESPONSE_Set_Cookie}" pattern="; SameSite=None" negate="true" />
          </preCondition>
        </preConditions>
      </outboundRules>
    </rewrite>
  </system.webServer>
</configuration>
Run Code Online (Sandbox Code Playgroud)

更新 1:仅添加上述配置即可解决现代浏览器的问题,但我们意识到旧版本的 Micosoft Edge 和 Internet Explorer 仍然存在问题。

所以我们需要在 web.config 文件中为 sessionState 节点添加 cookieSameSite="None" 属性。

<sessionState cookieSameSite="None" />
Run Code Online (Sandbox Code Playgroud)

但是请注意此配置更改,因为较旧的 .net 框架版本不支持它并导致您的站点显示错误页面。

顺便说一下,我们在 IOS 12 中的浏览器仍然存在问题。但我认为这与这个已确认的错误有关

更新 2:有关 IOS 问题的可能修复,请参阅 zemien 的答案

更新 3:通过将我们的发现与 zemien 的答案中的建议相结合,我们提出了以下重写规则。我们一直在生产中使用这种配置。但请注意:对于兼容的浏览器,它使用“SameSite:None”属性标记所有 cookie,并排除不兼容浏览器的 SameSite 属性(如果存在)。这可能看起来很复杂,但我试图通过注释行进行解释。

这是我们在生产中使用的最终配置:

<configuration> 

  <system.webServer>

    <rewrite>

      <outboundRules>

        <preConditions>
          <!-- Browsers incompatible with SameSite=None -->
          <preCondition name="IncompatibleWithSameSiteNone" logicalGrouping="MatchAny">
            <add input="{HTTP_USER_AGENT}" pattern="(CPU iPhone OS 12)|(iPad; CPU OS 12)" />
            <add input="{HTTP_USER_AGENT}" pattern="(Chrome/5)|(Chrome/6)" />
            <add input="{HTTP_USER_AGENT}" pattern="( OS X 10_14).*(Version/).*((Safari)|(KHTML, like Gecko)$)" />
          </preCondition>

          <!-- Rest of the browsers are assumed to be compatible with SameSite=None -->
          <preCondition name="CompatibleWithSameSiteNone" logicalGrouping="MatchAll">
            <add input="{HTTP_USER_AGENT}" pattern="(CPU iPhone OS 12)|(iPad; CPU OS 12)" negate="true" />
            <add input="{HTTP_USER_AGENT}" pattern="(Chrome/5)|(Chrome/6)" negate="true" />
            <add input="{HTTP_USER_AGENT}" pattern="( OS X 10_14).*(Version/).*((Safari)|(KHTML, like Gecko)$)" negate="true" />
          </preCondition>

        </preConditions>

        <!-- Rule 1: Remove SameSite part from cookie for incompatible browsers if exists -->
        <rule name="Remove_SameSiteCookie_IfExists_ForLegacyBrowsers" preCondition="IncompatibleWithSameSiteNone">
          <match serverVariable="RESPONSE_Set-Cookie" pattern="(.*)(SameSite=.*)" />
          <action type="Rewrite" value="{R:1}" />
        </rule>

        <!-- Rule 2: Override SameSite's value to None if exists, for compatible browsers -->
        <rule name="Override_SameSiteCookie_IfExists_ForModernBrowsers" preCondition="CompatibleWithSameSiteNone">
          <match serverVariable="RESPONSE_Set-Cookie" pattern="(.*)(SameSite=.*)" />
          <action type="Rewrite" value="{R:1}; SameSite=None" />
        </rule>

        <!-- Rule 3: Add SameSite attribute with the value None if it does not exists, for compatible browsers -->
        <rule name="Add_SameSiteCookie_IfNotExists_ForModernBrowsers" preCondition="CompatibleWithSameSiteNone">
          <match serverVariable="RESPONSE_Set-Cookie" pattern=".*"/>
          <!-- Condition explanation: Cookie data contains some string value but does not contain SameSite attribute -->
          <conditions logicalGrouping="MatchAll">
            <add input="{R:0}" pattern="^(?!\s*$).+"/>
            <add input="{R:0}" pattern="SameSite=.*" negate="true"/>
          </conditions>
          <action type="Rewrite" value="{R:0}; SameSite=None" />
        </rule>

      </outboundRules>

    </rewrite>    

  </system.webServer>  

</configuration>
Run Code Online (Sandbox Code Playgroud)