Cookie的SameSite策略


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示例

假如一家銀行用以運行轉賬操作的URL地址如下:
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資金。

這種惡意的網址可以有很多種形式,藏身於網頁中的許多地方。此外,攻擊者也不需要控制放置惡意網址的網站。例如他可以將這種地址藏在論壇,博客等任何用戶生成內容的網站中。這意味着如果服務端沒有合適的防御措施的話,用戶即使訪問熟悉的可信網站也有受攻擊的危險。透過例子能夠看出,攻擊者並不能通過CSRF攻擊來直接獲取用戶的賬戶控制權,也不能直接竊取用戶的任何信息。他們能做到的, 是欺騙用戶瀏覽器,讓其以用戶的名義運行操作。

3、CSRF的原理

  

 

 

從上圖可以看出,要完成一次CSRF攻擊,受害者必須依次完成兩個步驟:

  1.登錄銀行affectedBank.com,並在本地生成Cookie。

  2.在不登出affectedBank.com的情況下,訪問危險網站Sns.com。   

4、CSRF的防御

CSRF的防御可以從服務端和客戶端兩方面着手,現在一般的CSRF防御都在服務端進行。

(1)檢查Referer字段

  • 原理

HTTP頭中有一個Referer字段,這個字段用以標明請求來源於哪個地址。以上文銀行操作為例,Referer字段地址通常應該是轉賬按鈕所在的網頁地址,應該也位於www.examplebank.com之下。而如果是CSRF攻擊傳來的請求,Referer字段會是包含惡意網址的地址,不會位於www.examplebank.com之下,這時候服務器就能識別出惡意的訪問。
  • 優點

簡單易行,工作量低,僅需要在關鍵訪問處增加一步校驗。
  • 缺點

這種辦法也有其局限性,因其完全依賴瀏覽器發送正確的Referer字段。雖然http協議對此字段的內容有明確的規定,但並無法保證來訪的瀏覽器的具體實現,亦無法保證瀏覽器沒有安全漏洞影響到此字段。並且也存在攻擊者攻擊某些瀏覽器,篡改其Referer字段的可能。

(2)添加校驗token

由於CSRF的本質在於攻擊者欺騙用戶去訪問自己設置的地址,所以如果要求在訪問敏感數據請求時,要求用戶瀏覽器提供不保存在cookie中,並且攻擊者無法偽造的數據作為校驗,那么攻擊者就無法再運行CSRF攻擊。這種數據通常是窗體中的一個數據項。服務器將其生成並附加在窗體中,其內容是一個偽隨機數。當客戶端通過窗體提交請求時,這個偽隨機數也一並提交上去以供校驗。正常的訪問時,客戶端瀏覽器能夠正確得到並傳回這個偽隨機數,而通過CSRF傳來的欺騙性攻擊中,攻擊者無從事先得知這個偽隨機數的值,服務端就會因為校驗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 不發送

設置了StrictLax以后,基本就杜絕了 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屬性。谷歌瀏覽器上的禁用操作如下:

  1. 在chrome瀏覽器地址欄輸入chrome://flags並回車
  2. 在搜索欄中輸入SameSite by default cookies搜索,並禁用如圖中的兩項設置,改為Disabled即可
  3. 點擊右下鍵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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM