ASP.NET Core で SameSite Cookie を使用する
作成者: Rick Anderson
SameSite は、クロスサイト リクエスト フォージェリ (CSRF) 攻撃に対して何らかの保護を提供するように設計された IETF のドラフト標準です。 最初のドラフトは 2016 年に作成され、2019 年にはドラフト標準が更新されました。 更新された標準は、以前の標準と下位互換性がありません。最も顕著な違いは次のとおりです。
- SameSite ヘッダーのない Cookie は、既定で
SameSite=Lax
として扱われます。 - クロスサイトでの
SameSite=None
の使用を許可するには、cookie を使う必要があります。 - また、
SameSite=None
をアサートする Cookie も、Secure
としてマークする必要があります。 <iframe>
を使用するアプリケーションでは、<iframe>
がクロスサイトのシナリオとして扱われるため、sameSite=Lax
Cookie やsameSite=Strict
Cookie に関する問題が発生する可能性があります。- 値
SameSite=None
は 2016 年の標準では許可されておらず、一部の実装でそのような Cookie をSameSite=Strict
として処理する原因となっています。 このドキュメントの「古いブラウザーのサポート」をご覧ください。
SameSite=Lax
設定は、ほとんどのアプリケーションの Cookie で機能します。 OpenID Connect (OIDC) やWS-Federation など、一部の認証形式では、既定で POST ベースのリダイレクトになります。 POST ベースのリダイレクトによって SameSite のブラウザー保護がトリガーされるため、これらのコンポーネントについては SameSite が無効になります。 要求のフロー方法の違いにより、ほとんどの OAuth ログインは影響を受けません。
Cookie を生成する各 ASP.NET Core コンポーネントでは、SameSite が適切かどうかを判断する必要があります。
SameSite と Identity
ASP.NET Core Identity は、IFrames
または OpenIdConnect
統合のような高度なシナリオを除き、SameSite Cookie の影響をほとんど受けません。
Identity
を使用する場合は、cookie プロバイダーの追加や services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
の呼び出しを "行わないでください"。これらは、Identity
によって行われます。
SameSite のテスト サンプル コード
次のサンプルをダウンロードしてテストできます。
サンプル | ドキュメント |
---|---|
.NET Core Razor Pages | ASP.NET Core 3.1 Razor Pages の SameSite cookie のサンプル |
sameSite 属性の .NET Core によるサポート
.NET Core では、SameSite の 2019 ドラフト標準がサポートされています。 開発者は、プログラムで HttpCookie.SameSite
プロパティを使用して、sameSite 属性の値を制御できます。 SameSite
プロパティを Strict
、Lax
、または None
に設定すると、それらの値が cookie でネットワークに書き込まれます。 SameSiteMode.Unspecified
に設定すると、sameSite を cookie で送信してはならないことを示します。
var cookieOptions = new CookieOptions
{
// Set the secure flag, which Chrome's changes will require for SameSite none.
// Note this will also require you to be running on HTTPS.
Secure = true,
// Set the cookie to HTTP only which is good practice unless you really do need
// to access it client side in scripts.
HttpOnly = true,
// Add the SameSite attribute, this will emit the attribute with a value of none.
SameSite = SameSiteMode.None
// The client should follow its default cookie policy.
// SameSite = SameSiteMode.Unspecified
};
// Add the cookie to the response cookie collection
Response.Cookies.Append("MyCookie", "cookieValue", cookieOptions);
}
SameSite での API の使用
HttpContext.Response.Cookies.Append の既定値は Unspecified
です。つまり、SameSite 属性は cookie に追加されず、クライアントでは既定の動作 (新しいブラウザーの場合は Lax、古いブラウザーの場合は None) が使用されます。 次のコードでは、cookie の SameSite 値を SameSiteMode.Lax
に変更する方法が示されています。
HttpContext.Response.Cookies.Append(
"name", "value",
new CookieOptions() { SameSite = SameSiteMode.Lax });
Cookie を生成するすべての ASP.NET Core コンポーネントでは、シナリオに適した設定で、前の既定値がオーバーライドされます。 オーバーライドされた前の既定値は変更されません。
ASP.NET Core 3.1 以降では、次の SameSite のサポートが提供されます。
SameSite=None
を生成するSameSiteMode.None
の動作を再定義します- SameSite 属性を省略するための新しい値
SameSiteMode.Unspecified
を追加します。 - すべての Cookie API は、既定で
Unspecified
に設定されます。 Cookie を使用する一部のコンポーネントでは、シナリオに対しより具体定な値を設定します。 例については、上記の表をご覧ください。
ASP.NET Core 3.0 以降では、クライアントの既定値との競合を回避するため、SameSite の既定値が変更されました。 次の API では、これらの Cookie に SameSite 属性が生成されないように、既定値が SameSiteMode.Lax
から -1
に変更されました。
- HttpContext.Response.Cookies.Append で使用される CookieOptions
CookieOptions
のファクトリとして使用される CookieBuilder- CookiePolicyOptions.MinimumSameSitePolicy
履歴と変更
SameSite のサポートは、2016 年のドラフト標準を使用する ASP.NET Core 2.0 で最初に実装されました。 2016 年の標準はオプトインでした。 ASP.NET Core は、複数の Cookie を既定で Lax
に設定することによりオプトインしました。 認証に関するいくつかのイシューが発生した後、SameSite のほとんどの使用は無効にされました。
2019 年 11 月にパッチが発行されて、2016 標準から 2019 標準に更新されました。 SameSite 仕様の 2019 ドラフト:
- 2016 ドラフトとの下位互換性はありません。 詳しくは、このドキュメントの「古いブラウザーのサポート」をご覧ください。
- Cookie が既定で
SameSite=Lax
として扱われることが指定されています。 - クロスサイト配信を有効にするために
SameSite=None
を明示的にアサートする Cookie をSecure
としてマークする必要があることが指定されています。None
は、オプトアウトする新しいエントリです。 - ASP.NET Core 2.1、2.2、3.0 に対して発行されたパッチによってサポートされます。 ASP.NET Core 3.1 以降には、SameSite の追加サポートがあります。
- 2020 年 2 月に、Chrome によって既定で有効にされる予定です。 この標準へのブラウザーの移行は、2019 年に開始されました。
SameSite の 2016 ドラフト標準から 2019 ドラフト標準への変更によって影響を受ける API
- Http.SameSiteMode
- CookieOptions.SameSite
- CookieBuilder.SameSite
- CookiePolicyOptions.MinimumSameSitePolicy
- Microsoft.Net.Http.Headers.SameSiteMode
- Microsoft.Net.Http.Headers.SetCookieHeaderValue.SameSite
古いブラウザーのサポート
2016 SameSite 標準では、不明な値を SameSite=Strict
値として扱う必要がありました。 2016 SameSite 標準をサポートする古いブラウザーからアクセスされるアプリは、取得した SameSite プロパティの値が None
である場合、機能しなくなる可能性があります。 Web アプリで古いブラウザーをサポートする場合は、ブラウザーの検出を実装する必要があります。 User-Agents の値は揮発性が高く、頻繁に変更されるため、ASP.NET Core にはブラウザーの検出は実装されていません。 Microsoft.AspNetCore.CookiePolicy の拡張ポイントを使用すると、User-Agent 固有のロジックを接続できます。
Program.cs
では、UseAuthentication または Cookie を書き込むあらゆるメソッドを呼び出す前に、UseCookiePolicy を呼び出すコードを追加します。
var builder = WebApplication.CreateBuilder(args);
builder.Services.Configure<CookiePolicyOptions>(options =>
{
options.MinimumSameSitePolicy = SameSiteMode.Unspecified;
options.OnAppendCookie = cookieContext =>
CheckSameSite(cookieContext.Context, cookieContext.CookieOptions);
options.OnDeleteCookie = cookieContext =>
CheckSameSite(cookieContext.Context, cookieContext.CookieOptions);
});
void CheckSameSite(HttpContext httpContext, CookieOptions options)
{
if (options.SameSite == SameSiteMode.None)
{
var userAgent = httpContext.Request.Headers["User-Agent"].ToString();
if (MyUserAgentDetectionLib.DisallowsSameSiteNone(userAgent))
{
options.SameSite = SameSiteMode.Unspecified;
}
}
}
builder.Services.AddRazorPages();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCookiePolicy();
app.UseAuthorization();
app.MapRazorPages();
app.Run();
次の強調表示されたコードのようなコードを、Program.cs
に追加します。
var builder = WebApplication.CreateBuilder(args);
builder.Services.Configure<CookiePolicyOptions>(options =>
{
options.MinimumSameSitePolicy = SameSiteMode.Unspecified;
options.OnAppendCookie = cookieContext =>
CheckSameSite(cookieContext.Context, cookieContext.CookieOptions);
options.OnDeleteCookie = cookieContext =>
CheckSameSite(cookieContext.Context, cookieContext.CookieOptions);
});
void CheckSameSite(HttpContext httpContext, CookieOptions options)
{
if (options.SameSite == SameSiteMode.None)
{
var userAgent = httpContext.Request.Headers["User-Agent"].ToString();
if (MyUserAgentDetectionLib.DisallowsSameSiteNone(userAgent))
{
options.SameSite = SameSiteMode.Unspecified;
}
}
}
builder.Services.AddRazorPages();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCookiePolicy();
app.UseAuthorization();
app.MapRazorPages();
app.Run();
前のサンプルの MyUserAgentDetectionLib.DisallowsSameSiteNone
は、ユーザー エージェントで SameSite None
がサポートされていないかどうかを検出する、ユーザー提供のライブラリです。
if (MyUserAgentDetectionLib.DisallowsSameSiteNone(userAgent))
{
options.SameSite = SameSiteMode.Unspecified;
}
次のコードは、DisallowsSameSiteNone
メソッドのサンプルです。
警告
次のコードは、デモのみを目的としたものです。
- 完全なものと考えないでください。
- メンテナンスもサポートもされません。
public static bool DisallowsSameSiteNone(string userAgent)
{
// Check if a null or empty string has been passed in, since this
// will cause further interrogation of the useragent to fail.
if (String.IsNullOrWhiteSpace(userAgent))
return false;
// Cover all iOS based browsers here. This includes:
// - Safari on iOS 12 for iPhone, iPod Touch, iPad
// - WkWebview on iOS 12 for iPhone, iPod Touch, iPad
// - Chrome on iOS 12 for iPhone, iPod Touch, iPad
// All of which are broken by SameSite=None, because they use the iOS networking
// stack.
if (userAgent.Contains("CPU iPhone OS 12") ||
userAgent.Contains("iPad; CPU OS 12"))
{
return true;
}
// Cover Mac OS X based browsers that use the Mac OS networking stack.
// This includes:
// - Safari on Mac OS X.
// This does not include:
// - Chrome on Mac OS X
// Because they do not use the Mac OS networking stack.
if (userAgent.Contains("Macintosh; Intel Mac OS X 10_14") &&
userAgent.Contains("Version/") && userAgent.Contains("Safari"))
{
return true;
}
// Cover Chrome 50-69, because some versions are broken by SameSite=None,
// and none in this range require it.
// Note: this covers some pre-Chromium Edge versions,
// but pre-Chromium Edge does not require SameSite=None.
if (userAgent.Contains("Chrome/5") || userAgent.Contains("Chrome/6"))
{
return true;
}
return false;
}
アプリで SameSite の問題をテストする
サードパーティ ログインなどを介してリモート サイトとやり取りするアプリでは、以下を行う必要があります。
- 複数のブラウザーでやり取りをテストします。
- このドキュメントで説明されている CookiePolicy のブラウザー検出と軽減策を適用します。
新しい 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-cookies
を Enabled に切り替えます。 古いバージョンの 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 の更新)」をご覧ください
Safari についてテストする
Safari 12 では以前のドラフトが厳密に実装されており、cookie が新しい値 None
になっていると失敗します。 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 の古い標準がサポートされています。 Edge バージョン 44 には、新しい標準に関する既知の互換性の問題はありません。
Edge (Chromium) についてテストする
SameSite のフラグは、edge://flags/#same-site-by-default-cookies
ページで設定されます。 Edge Chromium では互換性の問題は検出されませんでした。
Electron についてテストする
Electron の複数のバージョンには、Chromium の古いバージョンが含まれています。 たとえば、Teams で使用されている Electron のバージョンは Chromium 66 であり、以前の動作を示しています。 お使いの製品に使用されている Electron のバージョンを使って、互換性テストを実行する必要があります。 「古いブラウザーのサポート」をご覧ください。
その他の技術情報
サンプル | ドキュメント |
---|---|
.NET Core Razor Pages | ASP.NET Core 3.1 Razor Pages の SameSite cookie のサンプル |
次のサンプルをダウンロードしてテストできます。
サンプル | ドキュメント |
---|---|
.NET Core Razor Pages | ASP.NET Core 3.1 Razor Pages の SameSite cookie のサンプル |
sameSite 属性の .NET Core によるサポート
.NET Core 3.1 以降では、SameSite の 2019 ドラフト標準がサポートされています。 開発者は、プログラムで HttpCookie.SameSite
プロパティを使用して、sameSite 属性の値を制御できます。 SameSite
プロパティを Strict、Lax、または None に設定すると、それらの値が cookie でネットワークに書き込まれます。 それを (SameSiteMode)(-1)
に設定すると、sameSite 属性を cookie でネットワークに含めてはならないことを示します
var cookieOptions = new CookieOptions
{
// Set the secure flag, which Chrome's changes will require for SameSite none.
// Note this will also require you to be running on HTTPS.
Secure = true,
// Set the cookie to HTTP only which is good practice unless you really do need
// to access it client side in scripts.
HttpOnly = true,
// Add the SameSite attribute, this will emit the attribute with a value of none.
// To not emit the attribute at all set
// SameSite = (SameSiteMode)(-1)
SameSite = SameSiteMode.None
};
// Add the cookie to the response cookie collection
Response.Cookies.Append("MyCookie", "cookieValue", cookieOptions);
.NET Core 3.1 以降では、更新された SameSite 値がサポートされ、追加の列挙値 SameSiteMode.Unspecified
が SameSiteMode
列挙型に追加されます。
この新しい値は、sameSite を cookie で送信してはならないことを示します。
SameSite での API の使用
HttpContext.Response.Cookies.Append の既定値は Unspecified
です。つまり、SameSite 属性は cookie に追加されず、クライアントでは既定の動作 (新しいブラウザーの場合は Lax、古いブラウザーの場合は None) が使用されます。 次のコードでは、cookie の SameSite 値を SameSiteMode.Lax
に変更する方法が示されています。
HttpContext.Response.Cookies.Append(
"name", "value",
new CookieOptions() { SameSite = SameSiteMode.Lax });
Cookie を生成するすべての ASP.NET Core コンポーネントでは、シナリオに適した設定で、前の既定値がオーバーライドされます。 オーバーライドされた前の既定値は変更されません。
ASP.NET Core 3.1 以降では、次の SameSite のサポートが提供されます。
SameSite=None
を生成するSameSiteMode.None
の動作を再定義します- SameSite 属性を省略するための新しい値
SameSiteMode.Unspecified
を追加します。 - すべての Cookie API は、既定で
Unspecified
に設定されます。 Cookie を使用する一部のコンポーネントでは、シナリオに対しより具体定な値を設定します。 例については、上記の表をご覧ください。
ASP.NET Core 3.0 以降では、クライアントの既定値との競合を回避するため、SameSite の既定値が変更されました。 次の API では、これらの Cookie に SameSite 属性が生成されないように、既定値が SameSiteMode.Lax
から -1
に変更されました。
- HttpContext.Response.Cookies.Append で使用される CookieOptions
CookieOptions
のファクトリとして使用される CookieBuilder- CookiePolicyOptions.MinimumSameSitePolicy
履歴と変更
SameSite のサポートは、2016 年のドラフト標準を使用する ASP.NET Core 2.0 で最初に実装されました。 2016 年の標準はオプトインでした。 ASP.NET Core は、複数の Cookie を既定で Lax
に設定することによりオプトインしました。 認証に関するいくつかのイシューが発生した後、SameSite のほとんどの使用は無効にされました。
2019 年 11 月にパッチが発行されて、2016 標準から 2019 標準に更新されました。 SameSite 仕様の 2019 ドラフト:
- 2016 ドラフトとの下位互換性はありません。 詳しくは、このドキュメントの「古いブラウザーのサポート」をご覧ください。
- Cookie が既定で
SameSite=Lax
として扱われることが指定されています。 - クロスサイト配信を有効にするために
SameSite=None
を明示的にアサートする Cookie をSecure
としてマークする必要があることが指定されています。None
は、オプトアウトする新しいエントリです。 - ASP.NET Core 2.1、2.2、3.0 に対して発行されたパッチによってサポートされます。 ASP.NET Core 3.1 には、SameSite の追加サポートがあります。
- 2020 年 2 月に、Chrome によって既定で有効にされる予定です。 この標準へのブラウザーの移行は、2019 年に開始されました。
SameSite の 2016 ドラフト標準から 2019 ドラフト標準への変更によって影響を受ける API
- Http.SameSiteMode
- CookieOptions.SameSite
- CookieBuilder.SameSite
- CookiePolicyOptions.MinimumSameSitePolicy
- Microsoft.Net.Http.Headers.SameSiteMode
- Microsoft.Net.Http.Headers.SetCookieHeaderValue.SameSite
古いブラウザーのサポート
2016 SameSite 標準では、不明な値を SameSite=Strict
値として扱う必要がありました。 2016 SameSite 標準をサポートする古いブラウザーからアクセスされるアプリは、取得した SameSite プロパティの値が None
である場合、機能しなくなる可能性があります。 Web アプリで古いブラウザーをサポートする場合は、ブラウザーの検出を実装する必要があります。 User-Agents の値は揮発性が高く、頻繁に変更されるため、ASP.NET Core にはブラウザーの検出は実装されていません。 Microsoft.AspNetCore.CookiePolicy の拡張ポイントを使用すると、User-Agent 固有のロジックを接続できます。
Startup.Configure
では、UseAuthentication または Cookie を書き込むあらゆるメソッドを呼び出す前に、UseCookiePolicy を呼び出すコードを追加します。
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCookiePolicy();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
});
}
Startup.ConfigureServices
では、次のようなコードを追加します。
public void ConfigureServices(IServiceCollection services)
{
services.Configure<CookiePolicyOptions>(options =>
{
options.MinimumSameSitePolicy = SameSiteMode.Unspecified;
options.OnAppendCookie = cookieContext =>
CheckSameSite(cookieContext.Context, cookieContext.CookieOptions);
options.OnDeleteCookie = cookieContext =>
CheckSameSite(cookieContext.Context, cookieContext.CookieOptions);
});
services.AddRazorPages();
}
private void CheckSameSite(HttpContext httpContext, CookieOptions options)
{
if (options.SameSite == SameSiteMode.None)
{
var userAgent = httpContext.Request.Headers["User-Agent"].ToString();
if (MyUserAgentDetectionLib.DisallowsSameSiteNone(userAgent))
{
options.SameSite = SameSiteMode.Unspecified;
}
}
}
前のサンプルの MyUserAgentDetectionLib.DisallowsSameSiteNone
は、ユーザー エージェントで SameSite None
がサポートされていないかどうかを検出する、ユーザー提供のライブラリです。
if (MyUserAgentDetectionLib.DisallowsSameSiteNone(userAgent))
{
options.SameSite = SameSiteMode.Unspecified;
}
次のコードは、DisallowsSameSiteNone
メソッドのサンプルです。
警告
次のコードは、デモのみを目的としたものです。
- 完全なものと考えないでください。
- メンテナンスもサポートもされません。
public static bool DisallowsSameSiteNone(string userAgent)
{
// Check if a null or empty string has been passed in, since this
// will cause further interrogation of the useragent to fail.
if (String.IsNullOrWhiteSpace(userAgent))
return false;
// Cover all iOS based browsers here. This includes:
// - Safari on iOS 12 for iPhone, iPod Touch, iPad
// - WkWebview on iOS 12 for iPhone, iPod Touch, iPad
// - Chrome on iOS 12 for iPhone, iPod Touch, iPad
// All of which are broken by SameSite=None, because they use the iOS networking
// stack.
if (userAgent.Contains("CPU iPhone OS 12") ||
userAgent.Contains("iPad; CPU OS 12"))
{
return true;
}
// Cover Mac OS X based browsers that use the Mac OS networking stack.
// This includes:
// - Safari on Mac OS X.
// This does not include:
// - Chrome on Mac OS X
// Because they do not use the Mac OS networking stack.
if (userAgent.Contains("Macintosh; Intel Mac OS X 10_14") &&
userAgent.Contains("Version/") && userAgent.Contains("Safari"))
{
return true;
}
// Cover Chrome 50-69, because some versions are broken by SameSite=None,
// and none in this range require it.
// Note: this covers some pre-Chromium Edge versions,
// but pre-Chromium Edge does not require SameSite=None.
if (userAgent.Contains("Chrome/5") || userAgent.Contains("Chrome/6"))
{
return true;
}
return false;
}
アプリで SameSite の問題をテストする
サードパーティ ログインなどを介してリモート サイトとやり取りするアプリでは、以下を行う必要があります。
- 複数のブラウザーでやり取りをテストします。
- このドキュメントで説明されている CookiePolicy のブラウザー検出と軽減策を適用します。
新しい 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-cookies
を Enabled に切り替えます。 古いバージョンの 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 の更新)」をご覧ください
Safari についてテストする
Safari 12 では以前のドラフトが厳密に実装されており、cookie が新しい値 None
になっていると失敗します。 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 の古い標準がサポートされています。 Edge バージョン 44 には、新しい標準に関する既知の互換性の問題はありません。
Edge (Chromium) についてテストする
SameSite のフラグは、edge://flags/#same-site-by-default-cookies
ページで設定されます。 Edge Chromium では互換性の問題は検出されませんでした。
Electron についてテストする
Electron の複数のバージョンには、Chromium の古いバージョンが含まれています。 たとえば、Teams で使用されている Electron のバージョンは Chromium 66 であり、以前の動作を示しています。 お使いの製品に使用されている Electron のバージョンを使って、互換性テストを実行する必要があります。 「古いブラウザーのサポート」をご覧ください。
その他の技術情報
サンプル | ドキュメント |
---|---|
.NET Core Razor Pages | ASP.NET Core 3.1 Razor Pages の SameSite cookie のサンプル |
次のサンプルをダウンロードしてテストできます。
サンプル | ドキュメント |
---|---|
.NET Core MVC | ASP.NET Core 2.1 MVC の SameSite cookie のサンプル |
.NET Core Razor Pages | ASP.NET Core 2.1 Razor Pages の SameSite cookie のサンプル |
12 月のパッチでの動作の変更
.NET Framework と .NET Core 2.1 での具体的な動作の変更は、SameSite
プロパティによる None
値の解釈方法です。 値 None
の意味は、パッチの前は "属性をまったく生成しない" で、パッチの後は "None
という値で属性を生成する" です。 パッチの後では、SameSite
の値が (SameSiteMode)(-1)
の場合は、属性は生成されません。
フォーム認証とセッション状態の Cookie に対する既定の SameSite 値が、None
から Lax
に変更されました。
SameSite での API の使用
HttpContext.Response.Cookies.Append の既定値は Unspecified
です。つまり、SameSite 属性は cookie に追加されず、クライアントでは既定の動作 (新しいブラウザーの場合は Lax、古いブラウザーの場合は None) が使用されます。 次のコードでは、cookie の SameSite 値を SameSiteMode.Lax
に変更する方法が示されています。
HttpContext.Response.Cookies.Append(
"name", "value",
new CookieOptions() { SameSite = SameSiteMode.Lax });
Cookie を生成するすべての ASP.NET Core コンポーネントでは、シナリオに適した設定で、前の既定値がオーバーライドされます。 オーバーライドされた前の既定値は変更されません。
履歴と変更
SameSite のサポートは、2016 年のドラフト標準を使用する ASP.NET Core 2.0 で最初に実装されました。 2016 年の標準はオプトインでした。 ASP.NET Core は、複数の Cookie を既定で Lax
に設定することによりオプトインしました。 認証に関するいくつかのイシューが発生した後、SameSite のほとんどの使用は無効にされました。
2019 年 11 月にパッチが発行されて、2016 標準から 2019 標準に更新されました。 SameSite 仕様の 2019 ドラフト:
- 2016 ドラフトとの下位互換性はありません。 詳しくは、このドキュメントの「古いブラウザーのサポート」をご覧ください。
- Cookie が既定で
SameSite=Lax
として扱われることが指定されています。 - クロスサイト配信を有効にするために
SameSite=None
を明示的にアサートする Cookie をSecure
としてマークする必要があることが指定されています。None
は、オプトアウトする新しいエントリです。 - ASP.NET Core 2.1、2.2、3.0 に対して発行されたパッチによってサポートされます。 ASP.NET Core 3.1 には、SameSite の追加サポートがあります。
- 2020 年 2 月に、Chrome によって既定で有効にされる予定です。 この標準へのブラウザーの移行は、2019 年に開始されました。
SameSite の 2016 ドラフト標準から 2019 ドラフト標準への変更によって影響を受ける API
- Http.SameSiteMode
- CookieOptions.SameSite
- CookieBuilder.SameSite
- CookiePolicyOptions.MinimumSameSitePolicy
- Microsoft.Net.Http.Headers.SameSiteMode
- Microsoft.Net.Http.Headers.SetCookieHeaderValue.SameSite
古いブラウザーのサポート
2016 SameSite 標準では、不明な値を SameSite=Strict
値として扱う必要がありました。 2016 SameSite 標準をサポートする古いブラウザーからアクセスされるアプリは、取得した SameSite プロパティの値が None
である場合、機能しなくなる可能性があります。 Web アプリで古いブラウザーをサポートする場合は、ブラウザーの検出を実装する必要があります。 User-Agents の値は揮発性が高く、頻繁に変更されるため、ASP.NET Core にはブラウザーの検出は実装されていません。 Microsoft.AspNetCore.CookiePolicy の拡張ポイントを使用すると、User-Agent 固有のロジックを接続できます。
Startup.Configure
では、UseAuthentication または Cookie を書き込むあらゆるメソッドを呼び出す前に、UseCookiePolicy を呼び出すコードを追加します。
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCookiePolicy();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
});
}
Startup.ConfigureServices
では、次のようなコードを追加します。
public void ConfigureServices(IServiceCollection services)
{
services.Configure<CookiePolicyOptions>(options =>
{
options.MinimumSameSitePolicy = (SameSiteMode)(-1);
options.OnAppendCookie = cookieContext =>
CheckSameSite(cookieContext.Context, cookieContext.CookieOptions);
options.OnDeleteCookie = cookieContext =>
CheckSameSite(cookieContext.Context, cookieContext.CookieOptions);
});
services.AddRazorPages();
}
private void CheckSameSite(HttpContext httpContext, CookieOptions options)
{
if (options.SameSite == SameSiteMode.None)
{
var userAgent = httpContext.Request.Headers["User-Agent"].ToString();
if (MyUserAgentDetectionLib.DisallowsSameSiteNone(userAgent))
{
options.SameSite = (SameSiteMode)(-1);
}
}
}
前のサンプルの MyUserAgentDetectionLib.DisallowsSameSiteNone
は、ユーザー エージェントで SameSite None
がサポートされていないかどうかを検出する、ユーザー提供のライブラリです。
if (MyUserAgentDetectionLib.DisallowsSameSiteNone(userAgent))
{
options.SameSite = SameSiteMode.Unspecified;
}
次のコードは、DisallowsSameSiteNone
メソッドのサンプルです。
警告
次のコードは、デモのみを目的としたものです。
- 完全なものと考えないでください。
- メンテナンスもサポートもされません。
public static bool DisallowsSameSiteNone(string userAgent)
{
// Check if a null or empty string has been passed in, since this
// will cause further interrogation of the useragent to fail.
if (String.IsNullOrWhiteSpace(userAgent))
return false;
// Cover all iOS based browsers here. This includes:
// - Safari on iOS 12 for iPhone, iPod Touch, iPad
// - WkWebview on iOS 12 for iPhone, iPod Touch, iPad
// - Chrome on iOS 12 for iPhone, iPod Touch, iPad
// All of which are broken by SameSite=None, because they use the iOS networking
// stack.
if (userAgent.Contains("CPU iPhone OS 12") ||
userAgent.Contains("iPad; CPU OS 12"))
{
return true;
}
// Cover Mac OS X based browsers that use the Mac OS networking stack.
// This includes:
// - Safari on Mac OS X.
// This does not include:
// - Chrome on Mac OS X
// Because they do not use the Mac OS networking stack.
if (userAgent.Contains("Macintosh; Intel Mac OS X 10_14") &&
userAgent.Contains("Version/") && userAgent.Contains("Safari"))
{
return true;
}
// Cover Chrome 50-69, because some versions are broken by SameSite=None,
// and none in this range require it.
// Note: this covers some pre-Chromium Edge versions,
// but pre-Chromium Edge does not require SameSite=None.
if (userAgent.Contains("Chrome/5") || userAgent.Contains("Chrome/6"))
{
return true;
}
return false;
}
アプリで SameSite の問題をテストする
サードパーティ ログインなどを介してリモート サイトとやり取りするアプリでは、以下を行う必要があります。
- 複数のブラウザーでやり取りをテストします。
- このドキュメントで説明されている CookiePolicy のブラウザー検出と軽減策を適用します。
新しい 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-cookies
を Enabled に切り替えます。 古いバージョンの 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 の更新)」をご覧ください
Safari についてテストする
Safari 12 では以前のドラフトが厳密に実装されており、cookie が新しい値 None
になっていると失敗します。 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 の古い標準がサポートされています。 Edge バージョン 44 には、新しい標準に関する既知の互換性の問題はありません。
Edge (Chromium) についてテストする
SameSite のフラグは、edge://flags/#same-site-by-default-cookies
ページで設定されます。 Edge Chromium では互換性の問題は検出されませんでした。
Electron についてテストする
Electron の複数のバージョンには、Chromium の古いバージョンが含まれています。 たとえば、Teams で使用されている Electron のバージョンは Chromium 66 であり、以前の動作を示しています。 お使いの製品に使用されている Electron のバージョンを使って、互換性テストを実行する必要があります。 「古いブラウザーのサポート」をご覧ください。
その他の技術情報
サンプル | ドキュメント |
---|---|
.NET Core MVC | ASP.NET Core 2.1 MVC の SameSite cookie のサンプル |
.NET Core Razor Pages | ASP.NET Core 2.1 Razor Pages の SameSite cookie のサンプル |
ASP.NET Core