ASP.NET 4.7.2 C# MVC の SameSite Cookie サンプル

.NET Framework 4.7 には SameSite 属性のサポートが組み込まれていますが、元の標準に準拠しています。 修正プログラムが適用された動作により、値をまったく出力するのではなく、SameSite.Noneの値を持つ属性を出力するようにNoneの意味が変更されました。 値を出力しない場合は、Cookie の SameSite プロパティを -1 に設定できます。

SameSite 属性の書き込み

Cookie に SameSite 属性を記述する方法の例を次に示します。

// Create the cookie
HttpCookie sameSiteCookie = new HttpCookie("SameSiteSample");

// Set a value for the cookieSite none.
// Note this will also require you to be running on HTTPS
sameSiteCookie.Value = "sample";

// Set the secure flag, which Chrome's changes will require for Same
sameSiteCookie.Secure = true;

// Set the cookie to HTTP only which is good practice unless you really do need
// to access it client side in scripts.
sameSiteCookie.HttpOnly = true;

// Add the SameSite attribute, this will emit the attribute with a value of none.
// To not emit the attribute at all set the SameSite property to -1.
sameSiteCookie.SameSite = SameSiteMode.None;

// Add the cookie to the response cookie collection
Response.Cookies.Add(sameSiteCookie);

英語以外の言語でこれを読んでいる場合は、ネイティブ言語でコード コメントを表示する場合は、この GitHub ディスカッションの問題 でお知らせください。

セッション状態の既定の sameSite 属性は、セッション設定の 'cookieSameSite' パラメーターで設定されます。 web.config

<system.web>
  <sessionState cookieSameSite="None">     
  </sessionState>
</system.web>

MVC 認証

OWIN MVC Cookie ベースの認証では、Cookie マネージャーを使用して Cookie 属性の変更を有効にします。 SameSiteCookieManager.csは、独自のプロジェクトにコピーできるこのようなクラスの実装です。

Microsoft.Owin コンポーネントがすべてバージョン 4.1.0 以降にアップグレードされていることを確認する必要があります。 たとえば、 packages.config ファイルを調べて、すべてのバージョン番号が一致していることを確認します。

<?xml version="1.0" encoding="utf-8"?>
<packages>
  <!-- other packages -->
  <package id="Microsoft.Owin.Host.SystemWeb" version="4.1.0" targetFramework="net472" />
  <package id="Microsoft.Owin.Security" version="4.1.0" targetFramework="net472" />
  <package id="Microsoft.Owin.Security.Cookies" version="4.1.0" targetFramework="net472" />
  <package id="Microsoft.Web.Infrastructure" version="1.0.0.0" targetFramework="net472" />
  <package id="Owin" version="1.0" targetFramework="net472" />
</packages>

その後、スタートアップ クラスで CookieManager を使用するように認証コンポーネントを構成する必要があります。

public void Configuration(IAppBuilder app)
{
    app.UseCookieAuthentication(new CookieAuthenticationOptions
    {
        CookieSameSite = SameSiteMode.None,
        CookieHttpOnly = true,
        CookieSecure = CookieSecureOption.Always,
        CookieManager = new SameSiteCookieManager(new SystemWebCookieManager())
    });
}

Cookie マネージャーは、それをサポートする コンポーネントに設定する必要があります。これには CookieAuthentication と OpenIdConnectAuthentication が含まれます。

SystemWebCookieManager は、応答 Cookie の統合に関する 既知の問題 を回避するために使用されます。

サンプルの実行

サンプル プロジェクトを実行した場合は、ブラウザー デバッガーを初期ページに読み込み、それを使用してサイトの Cookie コレクションを表示します。 Edge と Chrome でこれを行うには、F12 キーを押してから Application タブを選び、Cookies セクションの Storage オプションの下にあるサイト URL をクリックします。

ブラウザー デバッガーの Cookie の一覧

上の図から、[Cookie の作成] ボタンをクリックしたときにサンプルによって作成された Cookie の SameSite 属性値が Laxで、 サンプル コードに設定されている値と一致していることがわかります。

制御しない Cookie をインターセプトする

.NET 4.5.2 では、ヘッダーの書き込みをインターセプトするための新しいイベントが導入 Response.AddOnSendingHeaders。 これは、クライアント コンピューターに返される前に Cookie をインターセプトするために使用できます。 このサンプルでは、ブラウザーが新しい sameSite の変更をサポートしているかどうかをチェックする静的メソッドにイベントを接続し、サポートされていない場合は、新しい None 値が設定されている場合に属性を出力しないように Cookie を変更します。

イベントを処理し、独自のコードにコピーできる Cookie 属性を調整する例については、sameSite でイベントとSameSiteCookieRewriter.csをフックする例を参照してください。

public static void FilterSameSiteNoneForIncompatibleUserAgents(object sender)
{
    HttpApplication application = sender as HttpApplication;
    if (application != null)
    {
        var userAgent = application.Context.Request.UserAgent;
        if (SameSite.BrowserDetection.DisallowsSameSiteNone(userAgent))
        {
            HttpContext.Current.Response.AddOnSendingHeaders(context =>
            {
                var cookies = context.Response.Cookies;
                for (var i = 0; i < cookies.Count; i++)
                {
                    var cookie = cookies[i];
                    if (cookie.SameSite == SameSiteMode.None)
                    {
                        cookie.SameSite = (SameSiteMode)(-1); // Unspecified
                    }
                }
            });
        }
    }
}

特定の名前付き Cookie の動作は、ほとんど同じ方法で変更できます。次のサンプルでは、Lax値をサポートするブラウザーで既定の認証 Cookie をNoneからNoneに調整するか、Noneをサポートしていないブラウザーで同じSite 属性を削除します。

public static void AdjustSpecificCookieSettings()
{
    HttpContext.Current.Response.AddOnSendingHeaders(context =>
    {
        var cookies = context.Response.Cookies;
        for (var i = 0; i < cookies.Count; i++)
        {
            var cookie = cookies[i]; 
            // Forms auth: ".ASPXAUTH"
            // Session: "ASP.NET_SessionId"
            if (string.Equals(".ASPXAUTH", cookie.Name, StringComparison.Ordinal))
            { 
                if (SameSite.BrowserDetection.DisallowsSameSiteNone(userAgent))
                {
                    cookie.SameSite = -1;
                }
                else
                {
                    cookie.SameSite = SameSiteMode.None;
                }
                cookie.Secure = true;
            }
        }
    });
}

詳細情報

Chrome の更新プログラム

OWIN SameSite のドキュメント

ASP.NET ドキュメント

.NET SameSite の修正プログラム