SameSite是2016年對HTTP cookie的擴展旨在減輕跨站點請求偽造(CSRF)。原始設計是一種選擇加入功能,可以通過向cookie添加新的SameSite屬性來使用。Google發布的新版本將實施SameSite策略,下面將針對SameSite做個了解。
一、CSRF
1、CSRF是什么?
跨站請求偽造(英語:Cross-site request forgery),也被稱為 one-click attack 或者 session riding,通常縮寫為 CSRF 或者 XSRF, Cookie 往往用來存儲用戶的身份信息,惡意網站誘導用戶在當前已登錄的Web應用程序上執行操作,獲取Cookie中的信息,發送惡意請求。跟跨網站腳本(XSS)相比,XSS 利用的是用戶對指定網站的信任,CSRF 利用的是網站對用戶網頁瀏覽器的信任。
簡單地說,是攻擊者通過一些技術手段欺騙用戶的瀏覽器去訪問一個自己曾經認證過的網站並運行一些操作(如發郵件,發消息,甚至財產操作如轉賬和購買商品)。由於瀏覽器曾經認證過,所以被訪問的網站會認為是真正的用戶操作而去運行。這利用了web中用戶身份驗證的一個漏洞:簡單的身份驗證只能保證請求發自某個用戶的瀏覽器,卻不能保證請求本身是用戶自願發出的。
2、CSRF示例
http://www.examplebank.com/withdraw?account=AccoutName&amount=1000&for=PayeeName
<img src="http://www.examplebank.com/withdraw?account=Alice&amount=1000&for=Badman">
如果有賬戶名為Alice的用戶訪問了惡意站點,而她之前剛訪問過銀行不久,登錄信息尚未過期,那么她就會損失1000資金。
3、CSRF的原理

從上圖可以看出,要完成一次CSRF攻擊,受害者必須依次完成兩個步驟:
1.登錄銀行affectedBank.com,並在本地生成Cookie。
2.在不登出affectedBank.com的情況下,訪問危險網站Sns.com。
4、CSRF的防御
CSRF的防御可以從服務端和客戶端兩方面着手,現在一般的CSRF防御都在服務端進行。
(1)檢查Referer字段
-
原理
-
優點
-
缺點
(2)添加校驗token
二、SameSite 屬性
Cookie 的SameSite屬性用來限制第三方 Cookie,從而減少安全風險。谷歌瀏覽器已經實施SameSite策略。它可以設置如下三個值:Strict、Lax、None
1、Strict
Strict最為嚴格,完全禁止第三方 Cookie,跨站點時,任何情況下都不會發送 Cookie。換言之,只有當前網頁的 URL 與請求目標一致,才會帶上 Cookie。
Set-Cookie: CookieName=CookieValue; SameSite=Strict;
這個規則過於嚴格,可能造成非常不好的用戶體驗。比如,當前網頁有一個 GitHub 鏈接,用戶點擊跳轉就不會帶有 GitHub 的 Cookie,跳轉過去總是未登陸狀態。
2、Lax
Lax規則稍稍放寬,大多數情況也是不發送第三方 Cookie,但是導航到目標網址的 Get 請求除外。
Set-Cookie: CookieName=CookieValue; SameSite=Lax;
導航到目標網址的 GET 請求,只包括三種情況:鏈接,預加載請求,GET 表單。詳見下表。
| 請求類型 | 示例 | 正常情況 | Lax |
|---|---|---|---|
| 鏈接 | <a href="..."></a> |
發送 Cookie | 發送 Cookie |
| 預加載 | <link rel="prerender" href="..."/> |
發送 Cookie | 發送 Cookie |
| GET 表單 | <form method="GET" action="..."> |
發送 Cookie | 發送 Cookie |
| POST 表單 | <form method="POST" action="..."> |
發送 Cookie | 不發送 |
| iframe | <iframe src="..."></iframe> |
發送 Cookie | 不發送 |
| AJAX | $.get("...") |
發送 Cookie | 不發送 |
| Image | <img src="..."> |
發送 Cookie | 不發送 |
設置了Strict或Lax以后,基本就杜絕了 CSRF 攻擊。當然,前提是用戶瀏覽器支持 SameSite 屬性。新谷歌瀏覽器支持SameSite策略,並默認采用“Lax”
3、None
Chrome 計划將Lax變為默認設置。這時,網站可以選擇顯式關閉SameSite屬性,將其設為None。不過,前提是必須同時設置Secure屬性(Cookie 只能通過 HTTPS 協議發送),否則無效。
下面的設置無效:
Set-Cookie: widget_session=abc123; SameSite=None
下面的設置有效:
Set-Cookie: widget_session=abc123; SameSite=None; Secure
三、Chrome禁用掉SameSite
Google決定推進這項特性的使用。谷歌瀏覽器將支持SameSite策略。如果你使用的是谷歌瀏覽器,如果想保持之前處理cookie的方式,Chrome要求顯示指定SameSite=None。否則Chrome默認將視作SameSite=Lax。
如果你想禁用SameSite策略,請注意需要同時設置Secure屬性。谷歌瀏覽器上的禁用操作如下:
- 在chrome瀏覽器地址欄輸入chrome://flags並回車
- 在搜索欄中輸入SameSite by default cookies搜索,並禁用如圖中的兩項設置,改為Disabled即可
- 點擊右下鍵ReLaunch重啟瀏覽器即可

四、Chrome的SameSite策略對Ids4的影響以及解決方案
1、影響
如果你有一個單頁應用(SPA),使用另一域名的認證服務(比如IdentityServer4)進行身份認證,並且使用了所謂的靜默令牌刷新的話,你將受影響。登錄到認證服務的時候,它會為當前用戶設置會話cookie,這個cookie屬於認證服務域名。認證流程結束之后,另一域名會收到認證服務頒發的access token,有效期通常不會太長。當access token過期之后,應用無法訪問api,用戶需要頻繁的登錄,體驗十分差。
2、解決方案
為了避免這一情況,我們可以使用refresh_token實現靜默刷新。應用創建一個用戶不可見的iframe,在iframe中進行新的認證流程。iframe中加載了認證服務站點,當瀏覽器發送會話cookie的時候,認證服務識別出當前用戶然后頒發新的token。但是SPA網站使用iframe嵌入了認證服務站點的內容,這就是一個跨站請求,只有將iframe中屬於認證服務站點的cookie設置為SameSite=None,Chrome才會將iframe中的cookie發送到認證服務。否則,token靜默刷新將無法正常運行。
五、ASP.NET Core 中的 SameSite
1、定義類SameSiteExtention
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
namespace HyIdentityServer.Extention
{
// 文檔說明 https://devblogs.microsoft.com/aspnet/upcoming-samesite-cookie-changes-in-asp-net-and-asp-net-core/
public static partial class Extention
{
public static IServiceCollection AddSameSiteCookiePolicy(this 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);
});
return services;
}
private static void CheckSameSite(HttpContext httpContext, CookieOptions options)
{
if (options.SameSite == SameSiteMode.None)
{
var userAgent = httpContext.Request.Headers["User-Agent"].ToString();
if (DisallowsSameSiteNone(userAgent))
{
// For .NET Core < 3.1 set SameSite = (SameSiteMode)(-1)
options.SameSite = SameSiteMode.Unspecified;
}
}
}
private static bool DisallowsSameSiteNone(string userAgent)
{
bool result = 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"))
{
result = 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"))
{
result = 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"))
{
result = true;
}
return result;
}
}
}
2、Startup.cs中的注入
public void ConfigureServices(IServiceCollection services) { services.AddSameSiteCookiePolicy(); } public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { app.UseCookiePolicy(); }
參考資料:
1、https://docs.microsoft.com/zh-cn/aspnet/core/security/samesite?view=aspnetcore-3.1
2、https://devblogs.microsoft.com/aspnet/upcoming-samesite-cookie-changes-in-asp-net-and-asp-net-core/
3、https://www.cnblogs.com/holdengong/p/12591645.html
4、http://www.ruanyifeng.com/blog/2019/09/cookie-samesite.html
