在 ASP.NET Core 中使用 SameSite Cookie
SameSite 是 IETF 草稿標準,旨在提供對跨網站偽造要求 (CSRF) 攻擊的一些防禦。 最初於 2016 年制定草稿,草稿標準於 2019 年更新。 更新的標準不回溯相容於先前的標準,以下是最明顯的差異:
- 依預設會將沒有 SameSite 標頭的 cookies 視為
SameSite=Lax
。 - 必須使用
SameSite=None
以允許跨網站 cookie 使用。 - 判斷提示
SameSite=None
的 cookies 也必須標示為Secure
。 - 使用
<iframe>
的應用程式可能會遇到sameSite=Lax
或sameSite=Strict
cookies 的問題,因為<iframe>
會被視為跨網站案例。 - 值
SameSite=None
不受 2016 標準 的允許,而導致某些實作將這類 cookies 視為SameSite=Strict
。 請參閱本文件中的支援舊版瀏覽器。
SameSite=Lax
設定適用於大部分的應用程式 cookies。 某些形式的驗證 (例如 OpenID Connect (OIDC) 和 WS 同盟) 預設為 POST 型重新導向。 POST 型重新導向會觸發 SameSite 瀏覽器保護,因此對於這些元件會停用 SameSite。 大部分的 OAuth 登入並不會因為要求傳輸方式的差異而受到影響。
每個發出 cookies 的 ASP.NET Core 元件都必須確認 SameSite 是否適當。
SameSite 和 Identity
ASP.NET Core Identity 在很大程度上不受 SameSite cookies 影響,除了 IFrames
或 OpenIdConnect
整合等進階案例。
使用 Identity
時,請不要新增任何 cookie 提供者或呼叫 services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
,Identity
會代為處理。
SameSite 測試範例程式碼
下列範例可供下載並測試:
範例 | 文件 |
---|---|
.NET Core Razor Pages | ASP.NET Core 3.1 Razor Pages SameSite cookie 範例 |
.NET Core 對 sameSite 屬性的支援
.NET Core 支援 SameSite 的 2019 草稿標準。 開發人員可以使用 HttpCookie.SameSite
屬性,以程式設計方式控制 sameSite 屬性的值。 將 SameSite
屬性設定為 Strict
、Lax
或 None
,會導致這些值透過 cookie 寫入到網路上。 若設定為 SameSiteMode.Unspecified
,表示不應透過 cookie 傳送任何 sameSite。
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);
}
將 API 與 SameSite 搭配使用
HttpContext.Response.Cookies.Append 預設為 Unspecified
,這表示沒有任何 SameSite 屬性新增至 cookie ,且用戶端會使用其預設行為 (新瀏覽器為 Lax,舊瀏覽器為 None)。 下列程式碼說明如何將 cookie SameSite 值變更為 SameSiteMode.Lax
:
HttpContext.Response.Cookies.Append(
"name", "value",
new CookieOptions() { SameSite = SameSiteMode.Lax });
所有發出 cookies 的 ASP.NET Core 元件都會將前述預設值覆寫為適合其案例的設定。 被覆寫的前述預設值並未變更。
ASP.NET Core 3.1 和更新版本提供下列 SameSite 支援:
- 重新定義
SameSiteMode.None
發出SameSite=None
的行為 - 新增會省略 SameSite 屬性的新值
SameSiteMode.Unspecified
。 - 所有 Cookie API 預設為
Unspecified
。 某些使用 cookies 的元件會依據其案例設定更明確的值。 如需範例,請參閱上表。
在 ASP.NET Core 3.0 和更新版本中,SameSite 預設值已變更,以避免與不一致的用戶端預設值發生衝突。 下列 API 已將預設值從 SameSiteMode.Lax
變更為 -1
,以避免針對這些 cookies 發出 SameSite 屬性:
- CookieOptions 與 HttpContext.Response.Cookies.Append搭配使用
- 作為
CookieOptions
處理站的 CookieBuilder - CookiePolicyOptions.MinimumSameSitePolicy
歷程記錄和變更
SameSite 支援最初在 ASP.NET Core 2.0 中使用 2016 草稿標準實作。 2016 標準可供選擇加入。 ASP.NET Core 藉由將數個 cookies 預設為 Lax
選擇加入。 在發生若干驗證問題之後,大部分的 SameSite 使用都已停用。
2019 年 11 月發行了修補檔,用以從 2016 標準更新為 2019 標準。 SameSite 規格的 2019 草稿:
- 不回溯相容於 2016 草稿。 如需詳細資訊,請參閱本文件中的支援舊版瀏覽器。
- 指定 cookies 預設被視為
SameSite=Lax
。 - 指定明確判斷提示
SameSite=None
以啟用跨網站傳遞的 cookies 應標示為Secure
。None
是要選擇退出的新項目。 - 受到針對 ASP.NET Core 2.1、2.2 和 3.0 發出的修補檔支援。 ASP.NET Core 3.1 和更新版本有額外的 SameSite 支援。
- 排定於 2020 年 2 月由 Chrome 依預設啟用。 瀏覽器於 2019 年開始移轉至此標準。
從 2016 SameSite 草稿標準變更為 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 標準的舊版瀏覽器存取的應用程式在取得值為 None
的 SameSite 屬性時可能會中斷。 如果 Web 應用程式預定要支援舊版瀏覽器,則必須實作瀏覽器偵測。 ASP.NET Core 不會實作瀏覽器偵測,因為 User-Agents 值非常不穩定,經常變更。 Microsoft.AspNetCore.CookiePolicy 中的擴充點允許插入 User-Agent 特定邏輯。
在 Program.cs
中新增程式碼,以在呼叫 UseAuthentication 或 任何會寫入 cookies 的 方法之前呼叫 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+ 的暫時風險降低允許存留期不到兩分鐘的 cookies。 已啟用適當測試旗標的 Chrome 76 或 77 可提供更精確的結果。 若要測試新的 SameSite 行為,請將 chrome://flags/#same-site-by-default-cookies
切換為 [啟用]。 系統回報舊版的 Chrome (75 和更低版本) 在使用新的 None
設定時會失敗。 請參閱本文件中的支援舊版瀏覽器。
Google 不提供較舊的 Chrome 版本。 請依照下載 Chromium 中的指示,對舊版 Chrome 進行測試。 請不要用搜尋舊版 Chrome 所獲得的連結來下載 Chrome。
從 Canary 版本 80.0.3975.0
開始,可以基於測試目的使用新旗標 --enable-features=SameSiteDefaultChecksMethodRigorously
將 Lax+POST 暫時性緩和措施停用,以便在功能已移除緩和措施的最終狀態下測試站台和服務。 如需詳細資訊,請參閱 Chromium Projects 的 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 範例 |
.NET Core 對 sameSite 屬性的支援
.NET Core 3.1 和更新版本支援 SameSite 的 2019 草稿標準。 開發人員可以使用 HttpCookie.SameSite
屬性,以程式設計方式控制 sameSite 屬性的值。 將 SameSite
屬性設定為 Strict、Lax 或 None,會導致這些值透過 cookie 寫入到網路上。 將其設定為等於 (SameSiteMode)(-1)
,表示不應透過 cookie 將任何 sameSite 屬性包含到網路上
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
列舉中新增了額外的列舉值 SameSiteMode.Unspecified
。
這個新值表示不應透過 cookie 傳送 sameSite。
將 API 與 SameSite 搭配使用
HttpContext.Response.Cookies.Append 預設為 Unspecified
,這表示沒有任何 SameSite 屬性新增至 cookie ,且用戶端會使用其預設行為 (新瀏覽器為 Lax,舊瀏覽器為 None)。 下列程式碼說明如何將 cookie SameSite 值變更為 SameSiteMode.Lax
:
HttpContext.Response.Cookies.Append(
"name", "value",
new CookieOptions() { SameSite = SameSiteMode.Lax });
所有發出 cookies 的 ASP.NET Core 元件都會將前述預設值覆寫為適合其案例的設定。 被覆寫的前述預設值並未變更。
ASP.NET Core 3.1 和更新版本提供下列 SameSite 支援:
- 重新定義
SameSiteMode.None
發出SameSite=None
的行為 - 新增會省略 SameSite 屬性的新值
SameSiteMode.Unspecified
。 - 所有 Cookie API 預設為
Unspecified
。 某些使用 cookies 的元件會依據其案例設定更明確的值。 如需範例,請參閱上表。
在 ASP.NET Core 3.0 和更新版本中,SameSite 預設值已變更,以避免與不一致的用戶端預設值發生衝突。 下列 API 已將預設值從 SameSiteMode.Lax
變更為 -1
,以避免針對這些 cookies 發出 SameSite 屬性:
- CookieOptions 與 HttpContext.Response.Cookies.Append搭配使用
- 作為
CookieOptions
處理站的 CookieBuilder - CookiePolicyOptions.MinimumSameSitePolicy
歷程記錄和變更
SameSite 支援最初在 ASP.NET Core 2.0 中使用 2016 草稿標準實作。 2016 標準可供選擇加入。 ASP.NET Core 藉由將數個 cookies 預設為 Lax
選擇加入。 在發生若干驗證問題之後,大部分的 SameSite 使用都已停用。
2019 年 11 月發行了修補檔,用以從 2016 標準更新為 2019 標準。 SameSite 規格的 2019 草稿:
- 不回溯相容於 2016 草稿。 如需詳細資訊,請參閱本文件中的支援舊版瀏覽器。
- 指定 cookies 預設被視為
SameSite=Lax
。 - 指定明確判斷提示
SameSite=None
以啟用跨網站傳遞的 cookies 應標示為Secure
。None
是要選擇退出的新項目。 - 受到針對 ASP.NET Core 2.1、2.2 和 3.0 發出的修補檔支援。 ASP.NET Core 3.1 有額外的 SameSite 支援。
- 排定於 2020 年 2 月由 Chrome 依預設啟用。 瀏覽器於 2019 年開始移轉至此標準。
從 2016 SameSite 草稿標準變更為 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 標準的舊版瀏覽器存取的應用程式在取得值為 None
的 SameSite 屬性時可能會中斷。 如果 Web 應用程式預定要支援舊版瀏覽器,則必須實作瀏覽器偵測。 ASP.NET Core 不會實作瀏覽器偵測,因為 User-Agents 值非常不穩定,經常變更。 Microsoft.AspNetCore.CookiePolicy 中的擴充點允許插入 User-Agent 特定邏輯。
在 Startup.Configure
中新增程式碼,以在呼叫 UseAuthentication 或 任何會寫入 cookies 的 方法之前呼叫 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+ 的暫時風險降低允許存留期不到兩分鐘的 cookies。 已啟用適當測試旗標的 Chrome 76 或 77 可提供更精確的結果。 若要測試新的 SameSite 行為,請將 chrome://flags/#same-site-by-default-cookies
切換為 [啟用]。 系統回報舊版的 Chrome (75 和更低版本) 在使用新的 None
設定時會失敗。 請參閱本文件中的支援舊版瀏覽器。
Google 不提供較舊的 Chrome 版本。 請依照下載 Chromium 中的指示,對舊版 Chrome 進行測試。 請不要用搜尋舊版 Chrome 所獲得的連結來下載 Chrome。
從 Canary 版本 80.0.3975.0
開始,可以基於測試目的使用新旗標 --enable-features=SameSiteDefaultChecksMethodRigorously
將 Lax+POST 暫時性緩和措施停用,以便在功能已移除緩和措施的最終狀態下測試站台和服務。 如需詳細資訊,請參閱 Chromium Projects 的 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)
,則不會發出屬性。
表單驗證和工作階段狀態 cookies 的預設 SameSite 值已從 None
變更為 Lax
。
將 API 與 SameSite 搭配使用
HttpContext.Response.Cookies.Append 預設為 Unspecified
,這表示沒有任何 SameSite 屬性新增至 cookie ,且用戶端會使用其預設行為 (新瀏覽器為 Lax,舊瀏覽器為 None)。 下列程式碼說明如何將 cookie SameSite 值變更為 SameSiteMode.Lax
:
HttpContext.Response.Cookies.Append(
"name", "value",
new CookieOptions() { SameSite = SameSiteMode.Lax });
所有發出 cookies 的 ASP.NET Core 元件都會將前述預設值覆寫為適合其案例的設定。 被覆寫的前述預設值並未變更。
歷程記錄和變更
SameSite 支援最初在 ASP.NET Core 2.0 中使用 2016 草稿標準實作。 2016 標準可供選擇加入。 ASP.NET Core 藉由將數個 cookies 預設為 Lax
選擇加入。 在發生若干驗證問題之後,大部分的 SameSite 使用都已停用。
2019 年 11 月發行了修補檔,用以從 2016 標準更新為 2019 標準。 SameSite 規格的 2019 草稿:
- 不回溯相容於 2016 草稿。 如需詳細資訊,請參閱本文件中的支援舊版瀏覽器。
- 指定 cookies 預設被視為
SameSite=Lax
。 - 指定明確判斷提示
SameSite=None
以啟用跨網站傳遞的 cookies 應標示為Secure
。None
是要選擇退出的新項目。 - 受到針對 ASP.NET Core 2.1、2.2 和 3.0 發出的修補檔支援。 ASP.NET Core 3.1 有額外的 SameSite 支援。
- 排定於 2020 年 2 月由 Chrome 依預設啟用。 瀏覽器於 2019 年開始移轉至此標準。
從 2016 SameSite 草稿標準變更為 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 標準的舊版瀏覽器存取的應用程式在取得值為 None
的 SameSite 屬性時可能會中斷。 如果 Web 應用程式預定要支援舊版瀏覽器,則必須實作瀏覽器偵測。 ASP.NET Core 不會實作瀏覽器偵測,因為 User-Agents 值非常不穩定,經常變更。 Microsoft.AspNetCore.CookiePolicy 中的擴充點允許插入 User-Agent 特定邏輯。
在 Startup.Configure
中新增程式碼,以在呼叫 UseAuthentication 或 任何會寫入 cookies 的 方法之前呼叫 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+ 的暫時風險降低允許存留期不到兩分鐘的 cookies。 已啟用適當測試旗標的 Chrome 76 或 77 可提供更精確的結果。 若要測試新的 SameSite 行為,請將 chrome://flags/#same-site-by-default-cookies
切換為 [啟用]。 系統回報舊版的 Chrome (75 和更低版本) 在使用新的 None
設定時會失敗。 請參閱本文件中的支援舊版瀏覽器。
Google 不提供較舊的 Chrome 版本。 請依照下載 Chromium 中的指示,對舊版 Chrome 進行測試。 請不要用搜尋舊版 Chrome 所獲得的連結來下載 Chrome。
從 Canary 版本 80.0.3975.0
開始,可以基於測試目的使用新旗標 --enable-features=SameSiteDefaultChecksMethodRigorously
將 Lax+POST 暫時性緩和措施停用,以便在功能已移除緩和措施的最終狀態下測試站台和服務。 如需詳細資訊,請參閱 Chromium Projects 的 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 範例 |