次の方法で共有


ASP.NET で SameSite Cookie を操作する

作成者: Rick Anderson

SameSite は、クロスサイト リクエスト フォージェリ (CSRF) 攻撃に対して何らかの保護を提供するように設計された IETF のドラフト標準です。 最初のドラフトは 2016 年に作成され、2019 年にはドラフト標準が更新されました。 更新された標準は、以前の標準と下位互換性がありません。最も顕著な違いは次のとおりです。

  • SameSite ヘッダーのない Cookie は、既定で SameSite=Lax として扱われます。
  • クロスサイトでの Cookie の使用を許可するには、SameSite=None を使用する必要があります。
  • また、SameSite=None をアサートする Cookie も、Secure としてマークする必要があります。
  • <iframe> を使用するアプリケーションでは、<iframe> がクロスサイトのシナリオとして扱われるため、sameSite=Lax Cookie や sameSite=Strict Cookie に関する問題が発生する可能性があります。
  • SameSite=None2016 年の標準では許可されておらず、一部の実装でそのような Cookie を SameSite=Strict として処理する原因となっています。 このドキュメントの「古いブラウザーのサポート」をご覧ください。

SameSite=Lax 設定は、ほとんどのアプリケーションの Cookie で機能します。 OpenID Connect (OIDC) やWS-Federation など、一部の認証形式では、既定で POST ベースのリダイレクトになります。 POST ベースのリダイレクトによって SameSite のブラウザー保護がトリガーされるため、これらのコンポーネントについては SameSite が無効になります。 要求のフロー方法の違いにより、ほとんどの OAuth ログインは影響を受けません。

Cookie を生成する各 ASP.NET コンポーネントを使用する場合は、SameSite が適切かどうかの判断が必要です。

2019 .Net SameSite 更新プログラムのインストール後に発生するアプリケーションに関する問題については、「既知の問題」を参照してください。

ASP.NET 4.7.2 および 4.8 での SameSite の使用

.NET 4.7.2 および 4.8 は、2019 年 12 月の更新プログラムのリリース以降、SameSite の 2019 年のドラフト標準をサポートしています。 開発者は、HttpCookie.SameSite プロパティを使用して SameSite ヘッダーの値をプログラムで制御できます。 SameSite プロパティを StrictLax、または None に設定すると、それらの値が Cookie とともにネットワークに書き込まれます。 それを (SameSiteMode)(-1) に同じく設定すると、ネットワーク上で SameSite ヘッダーを Cookie とともに含める必要がないことが示されます。 HttpCookie.Secure プロパティ、または構成ファイル内の "requireSSL" は、Cookie が Secure かどうかをマークするのに使用できます。

新しい HttpCookie インスタンスの既定値は、SameSite=(SameSiteMode)(-1)Secure=false となります。 これらの既定値は、system.web/httpCookies 構成セクションでオーバーライドできます。ここで、文字列 "Unspecified" は、(SameSiteMode)(-1) のフレンドリ構成のみの構文です。

<configuration>
 <system.web>
  <httpCookies sameSite="[Strict|Lax|None|Unspecified]" requireSSL="[true|false]" />
 <system.web>
<configuration>

また、ASP.Net では、匿名認証、フォーム認証、セッション状態、ロール管理という 4 つの機能に対して、4 つの固有の Cookie も発行しています。 実行時に取得されたこれらの Cookie のインスタンスは、他のすべての HttpCookie インスタンスと同様に、SameSite プロパティと Secure プロパティを使用して操作できます。 ただし、SameSite 標準のパッチワークが出現するため、これらの 4 つの機能の Cookie の構成オプションは一貫性がありません。 関連する構成セクションと属性と既定値を次に示します。 機能に SameSite または Secure に関連する属性がない場合、この機能は、上記の system.web/httpCookies セクションに構成されている既定値にフォールバックします。

<configuration>
 <system.web>
  <anonymousIdentification cookieRequireSSL="false" /> <!-- No config attribute for SameSite -->
  <authentication>
   <forms cookieSameSite="Lax" requireSSL="false" />
  </authentication>
  <sessionState cookieSameSite="Lax" /> <!-- No config attribute for Secure -->
  <roleManager cookieRequireSSL="false" /> <!-- No config attribute for SameSite -->
 <system.web>
<configuration>

: "Unspecified" は現時点、system.web/httpCookies@sameSite でのみ使用できます。 今後の更新では、前述の cookieSameSite に同様の構文を追加したいと考えています。 コードでの (SameSiteMode)(-1) の設定は、これらの Cookie のインスタンスで引き続き機能します。*

英語以外の言語でこの記事をお読みになっていて、コードのコメントをネイティブ言語でご覧になりたい場合は、この GitHub ディスカッションの問題でお知らせください。

.NET アプリをもう一度対象にする

.NET 4.7.2 以降を対象にするには、次の手順を実行します。

  • web.config に次が含まれていることを確認します。

    <system.web>
      <compilation targetFramework="4.7.2"/>
      <httpRuntime targetFramework="4.7.2"/>
    </system.web>
    
    
  • プロジェクト ファイルに正しい TargetFrameworkVersion が含まれていることを確認します。

    <TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
    

    .NET 移行ガイドでは、さらに詳しく説明しています。

  • プロジェクト内の NuGet パッケージが正しいフレームワーク バージョンを対象にしていることを確認します。 packages.config ファイルを調べると、正しいフレームワーク バージョンを確認できます。次に例を示します。

    <?xml version="1.0" encoding="utf-8"?>
    <packages>
      <package id="Microsoft.AspNet.Mvc" version="5.2.7" targetFramework="net472" />
      <package id="Microsoft.ApplicationInsights" version="2.4.0" targetFramework="net451" />
    </packages>
    

    前述の packages.config ファイルでは、Microsoft.ApplicationInsights パッケージは次のようになります。

    • .NET 4.5.1 を対象としています。
    • フレームワーク ターゲットを対象としている更新済みパッケージが存在している場合、targetFramework 属性は、net472 に更新されています。

4.7.2 よりも前の .NET バージョン

Microsoft では、同じサイト Cookie 属性を記述するため、4.7.2 以前の .NET バージョンをサポートしていません。 次を行うための信頼性の高い方法は見つかっていません。

  • ブラウザーのバージョンに基づいて属性が正しく記述されていることを確認する。
  • 以前のバージョンのフレームワークで認証 Cookie とセッション Cookie をインターセプトして調整する。

12 月のパッチでの動作の変更

.NET Framework での具体的な動作の変更は、SameSite プロパティを使用して None 値をどのように解釈するかという点です。

  • パッチを実行する前は、None の値は次のような意味でした。
    • 属性を決して出力しないでください。
  • パッチを実行すると、次のようになります。
    • None の値は、"None の値を含む属性を出力してください" という意味です。
    • (SameSiteMode)(-1)SameSite 値を使用すると、属性は出力されません。

フォーム認証とセッション状態の Cookie に対する既定の SameSite 値が、None から Lax に変更されました。

ブラウザーに対する変更の影響についての概要

パッチをインストールして SameSite.None を含む Cookie を発行すると、次の 2 つのいずれかが発生します。

  • Chrome v80 では、新しい実装に従い、この Cookie が処理されません。また、この Cookie に対して同じサイト制限は適用されません。
  • 新しい実装をサポートするように更新されていないブラウザーは、古い実装に従います。 古い実装では、次のように表示されます。
    • 理解できない値が表示された場合は、無視して、厳密な同じサイト制限に切り替えます。

そのため、アプリが Chrome で中断するか、他の多くの場所で中断します。

履歴と変更

SameSite のサポートが最初に実装されたのは、2016 年のドラフト標準が使用されている .NET 4.7.2 でした。

Windows の 2019 年 11 月 19 日の更新プログラムにより、.NET 4.7.2 以降では、2016 年標準から 2019 年標準に更新されました。 他のバージョンの Windows では、追加の更新プログラムが予定されています。 詳細については、「.NET Framework で SameSite をサポートする KB 記事」を参照してください。

SameSite 仕様の 2019 ドラフト:

  • 2016 ドラフトとの下位互換性はありません。 詳しくは、このドキュメントの「古いブラウザーのサポート」をご覧ください。
  • Cookie が既定で SameSite=Lax として扱われることを明示しています。
  • クロスサイト配信を有効にするために SameSite=None を明示的にアサートする Cookie を Secure としてマークする必要があることを明示しています。
  • 上記のナレッジ ベースの説明に従って発行されたパッチによってサポートされています。
  • 2020 年 2 月に、Chrome によって既定で有効にされる予定です。 この標準へのブラウザーの移行は、2019 年に開始されました。

既知の問題

2016 年と 2019 年のドラフト仕様には互換性がないため、2019 年 11 月の .Net Framework 更新プログラムには、破壊的となる可能性があるいくつかの変更が導入されています。

  • セッション状態とフォーム認証の Cookie は、未指定ではなくなり、ネットワークに Lax として書き込まれるようになりました。
    • ほとんどのアプリで SameSite=Lax Cookie は動作しますが、iframe を利用するサイト間またはアプリケーション間で POST 操作が行われるアプリでは、セッション状態またはフォーム承認の Cookie が想定どおり使用されていない場合があります。 これを解決するには、前述のように、適切な構成セクション内の cookieSameSite 値を変更します。
  • コードまたは構成で SameSite=None が明示的に設定されている HttpCookie は、Cookie で書き込まれた値を含むようになりましたが、以前は省略されていました。 これにより、2016 年のドラフト標準のみをサポートしている古いブラウザーでは、問題が発生する可能性があります。
    • SameSite=None Cookie を使用する 2019 年のドラフト標準をサポートしているブラウザーを対象にする場合は、それらも Secure とマークしないと認識されない可能性があることを覚えておいてください。
    • SameSite=None を書き込まない 2016 年の動作に戻すには、アプリ設定 aspnet:SupressSameSiteNone=true を使用します。 これは、アプリ内のすべての HttpCookie に適用されることに注意してください。

Azure App Service を使用すると .Net 4.7.2 アプリで SameSite の動作がどのように構成されるかについては、「Azure App Service — SameSite の Cookie 処理と .NET Framework 4.7.2 パッチ」を参照してください。

古いブラウザーのサポート

2016 SameSite 標準では、不明な値を SameSite=Strict 値として扱う必要がありました。 2016 SameSite 標準をサポートする古いブラウザーからアクセスされるアプリは、取得した SameSite プロパティの値が None である場合、機能しなくなる可能性があります。 Web アプリで古いブラウザーをサポートする場合は、ブラウザーの検出を実装する必要があります。 User-Agents の値は揮発性が高く、頻繁に変更されるため、ASP.NET にはブラウザーの検出が実装されていません。

問題を解決するための Microsoft のアプローチは、ブラウザーが Cookie をサポートしていないことがわかっている場合に、ブラウザー検出コンポーネントを実装して Cookie から sameSite=None 属性を削除できるようにすることです。 Google のアドバイスは、新しい属性を持つ Cookie と属性をまったく持たない Cookie という 2 つの Cookie を発行することでした。 しかし、Microsoft は、Google のアドバイスは限定的であると考えています。 一部のブラウザー、特にモバイル ブラウザーでは、サイトまたはドメイン名から送信できる Cookie の数は、非常に少なく制限されています。 複数の Cookie、特に認証 Cookie などの大規模な Cookie を送信すると、すぐにモバイル ブラウザーの制限に達してしまい、診断と修正が困難なアプリ エラーが発生することがあります。 さらに、フレームワークとして、サードパーティのコードとコンポーネントの大規模なエコシステムがあります。これは、2 つの Cookie のアプローチを使用するように更新されていない場合があります。

この GitHub リポジトリ内のサンプル プロジェクトで使用されているブラウザー検出コードは、2 つのファイルに含まれています

これらの検出は、2016 年標準をサポートしているもっとも一般的なブラウザー エージェントであり、属性は完全に削除する必要があります。 これは完全な実装を意図するものではありません。

  • テスト サイトに表示されないブラウザーがアプリに表示される場合があります。
  • 環境での必要性に応じて検出を追加できるように準備しておく必要があります。

検出の接続方法は、使用している .NET と Web フレームワークのバージョンによって異なります。 次のコードは、HttpCookie 呼び出しサイトで呼び出すことができます。

private void CheckSameSite(HttpContext httpContext, HttpCookie cookie)
{
    if (cookie.SameSite == SameSiteMode.None)
    {
        var userAgent = httpContext.Request.UserAgent;
        if (BrowserDetection.DisallowsSameSiteNone(userAgent))
        {
            cookie.SameSite = (SameSiteMode)(-1);
        }
    }
}

次の ASP.NET 4.7.2 SameSite Cookie のトピックを参照してください。

サイトで HTTPS へのリダイレクトが行われるようにする

ASP.NET 4.x、WebForms、MVC の場合、IIS の URL 書き換え機能を使用して、すべての要求を HTTPS へリダイレクトできます。 次の XML は、ルールの例を示しています。

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <system.webServer>
    <rewrite>
      <rules>
        <rule name="Redirect to https" stopProcessing="true">
          <match url="(.*)"/>
          <conditions>
            <add input="{HTTPS}" pattern="Off"/>
            <add input="{REQUEST_METHOD}" pattern="^get$|^head$" />
          </conditions>
          <action type="Redirect" url="https://{HTTP_HOST}/{R:1}" redirectType="Permanent"/>
        </rule>
      </rules>
    </rewrite>
  </system.webServer>
</configuration>

IIS URL 書き換えのオンプレミス インストールは、インストールが必要な場合のオプションの機能です。

アプリで SameSite の問題をテストする

サポートしているブラウザーでアプリをテストし、Cookie に関連するシナリオを実行する必要があります。 Cookie のシナリオには、通常、次を使用します

  • ログイン フォーム
  • Facebook、Azure AD、OAuth、OIDC などの外部ログイン メカニズム
  • 他のサイトからの要求を受け入れるページ
  • iframe に埋め込まれるように設計されたアプリ内のページ

Cookie がアプリで正しく作成、保持、削除されていることを確認する必要があります。

サードパーティ ログインなどを介してリモート サイトとやり取りするアプリでは、以下を行う必要があります。

新しい SameSite 動作にオプトインできるバージョンのクライアントを使って、Web アプリをテストします。 Chrome、Firefox、Chromium Edge のいずれにも、テストに使用できる新しいオプトイン機能フラグがあります。 アプリで SameSite のパッチを適用した後、古いクライアント バージョン (特に Safari) でテストします。 詳しくは、このドキュメントの「古いブラウザーのサポート」をご覧ください。

Chrome についてテストする

Chrome 78 以降では、一時的な軽減策が設定されているため、誤解を招く結果が得られます。 Chrome 78 以降の一時的な軽減策により、2 分未満の Cookie が許容されます。 適切なテスト フラグが有効にされた Chrome 76 または 77 では、より正確な結果が提供されます。 SameSite の新しい動作をテストするには、chrome://flags/#same-site-by-default-cookiesEnabled に切り替えます。 古いバージョンの Chrome (75 以前) では、新しい設定 None を使うと失敗することが報告されています。 このドキュメントの「古いブラウザーのサポート」をご覧ください。

Google では、以前のバージョンの Chrome は提供されていません。 Chromium のダウンロードに関するページの手順に従って、古いバージョンの Chrome をテストしてください。 Chrome の古いバージョンを検索して示されるリンクからは、Chrome をダウンロードしないでください

Canary バージョン 80.0.3975.0 以降では、新しいフラグ --enable-features=SameSiteDefaultChecksMethodRigorously を使用してテストのために Lax+POST の一時的な軽減策を無効にし、軽減策が削除された機能の最終的な状態でサイトとサービスをテストすることができます。 詳しくは、The Chromium Projects の「SameSite Updates (SameSite の更新)」をご覧ください

Chrome 80 以降を使用したテスト

新しい属性をサポートしている Chrome のバージョンをダウンロードします。 執筆時点での最新バージョンは、Chrome 80 です。 Chrome 80 では、新しい動作を使用するためにフラグ chrome://flags/#same-site-by-default-cookies が有効になっている必要があります。 また、sameSite 属性が有効になっていない Cookie の今後の動作をテストするために、(chrome://flags/#cookies-without-same-site-must-be-secure) を有効にする必要もあります。 Chrome 80 は、特定の要求に対して猶予期間が指定されていても、SameSite=Lax という属性を使用せずに Cookie を扱うように切り替えることになっています。 猶予期間の時間指定を無効にするには、次のコマンド ライン引数を使用して Chrome 80 を起動します。

--enable-features=SameSiteDefaultChecksMethodRigorously

sameSite 属性が見つからないという Chrome 80 の警告メッセージがブラウザー コンソールに表示されます。 F12 キーを使用してブラウザー コンソールを開きます。

Safari についてテストする

Safari 12 では以前のドラフトが厳密に実装されており、新しい None 値が Cookie 内にある場合は失敗します。 None は、このドキュメントの「古いブラウザーのサポート」のブラウザー検出コードを使用して回避されます。 MSAL、ADAL、または使用しているライブラリを使用して、Safari 12、Safari 13、WebKit ベースの OS スタイルのログインをテストします。 この問題は、基盤の OS バージョンによって変わります。 OSX Mojave (10.14) および iOS 12 には、SameSite の新しい動作との互換性の問題があることがわかっています。 OS を OSX Catalina (10.15) または iOS 13 にアップグレードすると、問題は解決します。 現在、Safari には新しい仕様の動作をテストするためのオプトイン フラグがありません。

Firefox についてテストする

Firefox による新しい標準のサポートは、バージョン 68 以降で、機能フラグ network.cookie.sameSite.laxByDefault を指定して about:config ページでオプトインすることでテストできます。 以前のバージョンの Firefox では、互換性の問題は報告されていません。

Edge (レガシ) ブラウザーを使用したテスト

Edge では、SameSite の古い標準がサポートされています。 バージョン 44 以降の Edge には、新しい標準に関する互換性の既知の問題はありません。

Edge (Chromium) についてテストする

SameSite のフラグは、edge://flags/#same-site-by-default-cookies ページで設定されます。 Edge Chromium では互換性の問題は検出されませんでした。

Electron を使用したテスト

Electron の複数のバージョンには、Chromium の古いバージョンが含まれています。 たとえば、Teams で使用されている Electron のバージョンは Chromium 66 であり、以前の動作を示します。 お使いの製品で使用されている Electron のバージョンとの互換性テストは、独自に実行する必要があります。 「古いブラウザーのサポート」を参照してください。

SameSite のパッチを元に戻す

.NET Framework アプリでは、更新された sameSite の動作を、None の値に対して sameSite 属性が出力されていなかった以前の動作に戻すことができます。また、認証とセッションの Cookie を元に戻して、値が出力されないようにすることができます。 Chrome の変更によって、標準に対する変更をサポートするブラウザーを使用しているユーザーの外部 POST 要求または認証が中断されるため、これは "非常に一時的な修正" と見なす必要があります。

.NET 4.7.2 の動作を元に戻す

web.config を、次の構成設定を含むように更新します。

<configuration> 
  <appSettings>
    <add key="aspnet:SuppressSameSiteNone" value="true" />
  </appSettings>
 
  <system.web> 
    <authentication> 
      <forms cookieSameSite="None" /> 
    </authentication> 
    <sessionState cookieSameSite="None" /> 
  </system.web> 
</configuration>

その他のリソース