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 屬性在 web.config
的工作階段設定中由 'CookieSameSite' 參數設定
<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
索引標籤,按一下 Storage
區段中 Cookies
選項底下的站台 URL。
從上圖可以看到,當您按一下「建立 Cookies」按鈕時,範例建立的 Cookie 的 SameSite 屬性值為 Lax
,與範例程式碼中設定的值相符。
攔截您無法控制的 Cookie
.NET 4.5.2 引入了一個用於攔截標頭寫入的新事件 Response.AddOnSendingHeaders
。 這可用於在 Cookie 傳回用戶端機器之前進行攔截。 在範例中,我們將事件連接到靜態方法,該方法會檢查瀏覽器是否支援新的 SameSite 變更,如果不支援,則將 Cookie 更改為在設定了新 None
值時不發出該屬性。
有關連線事件的範例,請參閱 global.asax;有關處理事件和調整 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 行為;下面的範例在支援 None
值的瀏覽器上將預設驗證 Cookie 從 Lax
調整為 None
,或在不支援 None
的瀏覽器上移除 SameSite 屬性。
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;
}
}
});
}