web-dev-qa-db-ja.com

ブラウザは、ペイメントゲートウェイのサイトへの投稿リクエストでASP.NET_SessionId Cookieを設定しません

Webアプリケーションの支払いプロセスで奇妙な問題が発生し、セッションデータが失われています。

このプロセスでは、チェックアウトページのユーザーが支払いプロバイダーのページにリダイレクトされ、サイトにアクセスするとすぐに(指定されたURLに)サイトにリダイレクトされます。この最後のリダイレクトは、基本的に私たちのサイトに投稿するフォームと、ページの読み込み時にそのフォームを投稿する数行のJavaScriptコードで構成される支払いプロバイダーのHTMLコードのブラウザーの評価によって行われます。この時点で、ブラウザはPOST要求を行いますが、まったく同じドメイン(アプリケーションのドメイン)に対して行われた以前の要求に存在する "ASP.NET_SessionId" Cookieを設定しません。さらに奇妙なのは、「AcceptCookie」という名前の別のCookieを設定することです。 「ASP.NET_SessionId」Cookieをドロップすることを選択するだけです。

状況を説明するために、スクリーンショットをいくつか撮りました。 (これらのスクリーンショットでは、オレンジと緑の長方形にまったく同じ値が含まれています。)

  1. これは、ユーザーが「チェックアウト」ボタンを押したときに(アプリケーションに対して)行われた要求です。このリクエストの後、ユーザーは支払いプロバイダーのページにリダイレクトされます。

チェックアウトリクエスト

  1. これは、ユーザーがそこで完了した後に支払いプロバイダーによって提供される最後のページです。ご覧のとおり、ページの読み込み時にドメインに自動的に投稿されるのは単純なフォームです。

支払いプロバイダーの最終応答

  1. ただし、この投稿リクエストには「ASP.NET_SessionId」Cookieが含まれていないため、新しいセッションIDが取得され、以前のセッションデータが失われます。繰り返しますが、「ASP.NET_SessionId」だけが欠落しており、「AcceptCookie」という名前のものは欠落しています。

ユーザーをサイトに戻すリクエストを送信します(前のステップでJavaScriptを使用して作成)

最後に、古いバージョンのブラウザではこの問題は発生しないことを突き止めました。 Firefox 52では魅力的に機能しますが、Firefox 71では上記の問題が発生します。

何か案は?

注:これは、targetFramework = "4.5.2"を含むASP.NET MVCアプリケーションです。

ごきげんよう。

12
E. Özgür

私たちはそれを理解しました。

どういうわけか「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>

UPDATE 1:上記の構成を追加するだけで、最新のブラウザーの問題は解決しましたが、Micosoft EdgeとInternet Explorerの古いバージョンではまだ問題が発生していることがわかりました。

そのため、web.configファイルのsessionStateノードにcookieSameSite = "None"属性を追加する必要がありました。

<sessionState cookieSameSite="None" />

ただし、この構成変更には注意してください。古い.netフレームワークバージョンではサポートされておらず、サイトにエラーページが表示されます。

ちなみに、IOS 12)のブラウザにはまだ問題がありますが、これは この確認済みのバグに関連していると思います

更新2:IOS問題に関する可能な修正についてはzemienの回答を参照してください

更新3:私たちの調査結果をzemienの回答の提案と組み合わせることにより、次の書き換えルールを作成しました。この構成は本番環境で使用しています。 ただし、互換性のあるブラウザの場合はすべてのCookieに「SameSite:None」属性が付けられ、互換性のないブラウザの場合は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>
14
E. Özgür

私はいくつかのSO回答を修正して、セッションCookieにSameSite=Noneを追加し、またSameSite=Noneallほとんどの互換性のないブラウザ用のCookie。この書き換えの目的は、Chrome 80より前の「レガシー」動作を維持することです。

私の完全な記事 Coder Frontline blog

<rewrite>
  <outboundRules>
    <preConditions>
      <!-- Checks User Agent to identify 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>
    </preConditions>

    <!-- Adds or changes SameSite to None for the session cookie -->
    <!-- Note that secure header is also required by Chrome and should not be added here -->
    <rule name="SessionCookieAddNoneHeader">
      <match serverVariable="RESPONSE_Set-Cookie" pattern="((.*)(ASP.NET_SessionId)(=.*))(SameSite=.*)?" />
      <action type="Rewrite" value="{R:1}; SameSite=None" />
    </rule>

    <!-- Removes SameSite=None header from all cookies, for most incompatible browsers -->
    <rule name="CookieRemoveSameSiteNone" preCondition="IncompatibleWithSameSiteNone">
      <match serverVariable="RESPONSE_Set-Cookie" pattern="(.*)(SameSite=None)" />
      <action type="Rewrite" value="{R:1}" />
    </rule>
  </outboundRules>
</rewrite>

これはほとんどのASP .NetおよびASP .Net Coreアプリケーションで機能しますが、新しいフレームワークには、この動作を制御するための適切なコードと構成オプションがあります。上記の私の書き換えを使用する前に、利用可能なすべてのオプションを調査することをお勧めします。

1
zemien