自Chrome 51版本开始,浏览器的 Cookies 新增了一个SameSite
属性,用来防止 CSRF 攻击和信息泄漏,更多信息参考chrome Feature: 'SameSite' cookie attribute。
简单回顾什么是CSRF攻击
Cookies
往往用来存储用户的身份信息,恶意网站通过设法伪造带有正确Cookies
进行 HTTP 请求,这就是 CSRF 攻击。
举例来说,用户登陆了银行网站your-bank.com
,银行服务器发来了一个 Cookie。
Set-Cookie: session_id=abc123;
用户后来又访问了恶意网站malicious-site.com
,恶意网站总是想方设法让你在恶意站点发送一个表单请求。
手段:中奖填写联系信息、透明的form表单提交按钮、附加在诱惑图片上的超链接
<form action="your-bank.com/transfer" method="POST">
...
</form>
用户一旦被诱骗发送这个表单,银行网站就会收到带有正确 Cookie 的请求。为了防止CSRF攻击,银行网站表单会设置一个隐藏域,表单提交时一起带上一个随机token至服务器,告诉服务器这是真实请求。
<form action="your-bank.com/transfer" method="POST">
<input type="hidden" name="token" value="dad3weg34">
...
</form>
之所以被CSRF攻击,是因为恶意网站诱导你在其页面上发送了第三方cookie(此时的银行网站cookie为第三方cookie),它除了用于 CSRF 攻击,还可以用于用户追踪。
第三方是一种相对概念,规定假定你正在访问的站点为第一方站点,则浏览器为第二方,其他网站就是第三方站点,第三方站点诱导你发送第一方站点的cookie时,我们就说此时的cookie为第三方cookie。
比如,Facebook 在第三方网站插入一张看不见的图片。
<img src="facebook.com" style="visibility:hidden;">
浏览器加载上面代码时,就会向 Facebook 发出带有 Cookie 的请求,从而 Facebook 就会知道你是谁,访问了什么网站。
SameSite
cookies机制一直被认为是不安全的,随着技术的更新,界内一直在完善cookies的安全机制,SameSite
属性是谷歌浏览器为完善cookies安全机制出的特性之一。
Cookie 的SameSite
属性用来限制第三方 Cookie的行为。
它可以设置三个值。
- Strict
- Lax
- None
Strict
Strict
最为严格,完全禁止第三方 Cookie,当当前站点与请求目标站点是跨站
关系时,总是不会发送 Cookie。换言之,只有当前站点 与请求目标站点是同站
关系时,才会带上 Cookie。
Set-Cookie: CookieName=CookieValue; SameSite=Strict;
这个规则过于严格,可能造成非常不好的用户体验。
举例说明:
假定你当前所处站点地址为https://obmq.com/index.html
,该站需要通过XHR请求获取某天气站点的未来7天的天气信息https://weather-forecast.org/api/weather?future=7
,该接口要求必须携带cookieSet-Cookie: vip=true; Path=/; HttpOnly; SameSite=Strict;
,这种情况下,你无论如何都无法在https://obmq.com
站点下发送这个XHR请求时还能携带上这个cookie,换句话说,你发送的接口请求的cookie请求头一定不会有vip=true
,即使你现在已经是该天气网站的vip。
None
None
在Chrome 85 版本之前是SameSite
的默认设置值,即Set-Cookie: key=value; SameSite=None
等于Set-Cookie: key=value
。
在Chrome 85 版本之前,显示设置SameSite=None
不需要设置Secure
属性,详细参见:Reject insecure SameSite=None cookies
在Chrome 85 版本以后,站点选择显式关闭SameSite
属性时,在将其值设为None
的同时。必须同时设置Secure
属性(表示Cookie 只能通过 HTTPS 协议发送),否则无效。
下面的设置有效。
Set-Cookie: widget_session=abc123; SameSite=None; Secure
下面的设置无效。
Set-Cookie: widget_session=abc123; SameSite=None
Lax
Chrome 在85版本后将Lax
设为SameSite
的默认值,即Set-Cookie: key=value; SameSite=Lax
等于Set-Cookie: key=value
,详细参见:Cookies default to SameSite=Lax。
Lax
规则比较宽松,大多数情况也不发送第三方 Cookie,但是导航到目标站点的 Get 请求除外。
Set-Cookie: CookieName=CookieValue; SameSite=Lax;
导航到目标站点的 GET 请求,只包括三种情况:链接,预加载请求,GET 表单。详见下表。
请求类型 | 示例 | SameSite=None;Secure | 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 | 不发送 |
xhr/fetch | $.get("...") | 发送 Cookie | 不发送 |
Image | <img src="..."> | 发送 Cookie | 不发送 |
Script | <script src="..."> | 发送Cookie | 不发送 |
设置了Strict
或Lax
以后,基本就杜绝了 CSRF 攻击。当然,前提是用户浏览器支持 SameSite
属性。
Schemeful Same-Site
自Chrome 86版本开始,考虑到不安全的http://
协议仍然为网络攻击者提供了篡改cookie的机会,然后将这些cookie用于站点安全的https://
。谷歌浏览器修改了cookie的Same Site
的定义,将在相同域名的安全(https://)协议和不安全(http://)协议作为是否跨站
的判断因素之一。详情参见Feature: Schemeful same-site
如果您的站点全面升级到https协议,那么下面的内容不适合您;如果您的站点是https协议和http协议混存,那么您需要关注。
常见的 "cross-scheme" Cookies携带情况
超链接
当Schemeful Same-Site
禁止时,从http:// site.example链接到
https