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