共计 6276 个字符,预计需要花费 16 分钟才能阅读完成。
自 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://site.example 时,即便SameSite=Strict
仍然会携带上 cookie。
当 Schemeful Same-Site
启用时,从 http:// site.example 链接到
https://site.example 时,SameSite=Strict
的 cookies 会被锁定,其余 cookies 携带的体现如下图和下表:
<figcaption style=”text-align: center;”>Cross-scheme navigation from HTTP to HTTPS.</figcaption>
<br/>
HTTP → HTTPS | HTTPS → HTTP | |
SameSite=Strict
|
⛔ Blocked | ⛔ Blocked |
SameSite=Lax
|
✓ Allowed | ✓ Allowed |
SameSite=None;Secure
|
✓ Allowed | ⛔ Blocked |
加载子资源
加载子资源的形式包含 images
, iframes
, 和XHR or Fetch
的网络申请。
加载子资源分为 http 加载 https 子资源
和https 加载子 http 资源
,携带 cookies 的体现如下图和下表:
当 Schemeful Same-Site
禁止时,加载子资源时,SameSite=Strict
或者 SameSite=Lax
的 cookie 会被携带上。
当 Schemeful Same-Site
启用时,加载子资源时,SameSite=Strict
或者 SameSite=Lax
的 cookies 会被锁定,其余 cookies 携带的体现如下图和下表:
<figcaption style=”text-align: center;”>An HTTP page including a cross-scheme subresource via HTTPS.</figcaption>
<br/>
HTTP → HTTPS | HTTPS → HTTP | |
SameSite=Strict
|
⛔ Blocked | ⛔ Blocked |
SameSite=Lax
|
⛔ Blocked | ⛔ Blocked |
SameSite=None;Secure
|
✓ Allowed | ⛔ Blocked |
POST 表单
当 Schemeful Same-Site
禁止时,发送 POST 表单时,SameSite=Strict
或者 SameSite=Lax
的 cookie 会被携带上。
当 Schemeful Same-Site
启用时,发送 POST 表单时,只有 SameSite=None
的 cookies 会被携带,其余 cookies 携带的体现如下图和下表:
<figcaption style=”text-align: center;”>Cross-scheme form submission from HTTP to HTTPS.</figcaption>
<br/>
HTTP → HTTPS | HTTPS → HTTP | |
SameSite=Strict
|
⛔ Blocked | ⛔ Blocked |
SameSite=Lax
|
⛔ Blocked | ⛔ Blocked |
SameSite=None;Secure
|
✓ Allowed | ⛔ Blocked |
对 WebSockets 的影响?
如果 WebSocket 连贯与页面的安全性雷同,则仍将被视为同站。
https://
连贯 wss://
被视为同站;http://
连贯 ws://
被视为同站,否则视为跨站。具体如下:
Same-site:
wss://
从https://
连贯ws://
从http://
连贯
Cross-site:
wss://
从http://
连贯ws://
从https://
连贯
最佳实际
仍然应用 token 机制避免 CSRF 攻打
设置了 SameSite 属性值为 Strict
或Lax
当前,根本杜绝了 CSRF 攻打。然而 SameSite 是 Cookies 属性之一,所以存在以下诸多限度:
- 要求浏览器必须兼容 Cookies 的 SameSite 属性
- 要求客户端利用必须反对 Cookies 机制,比方 APP 和微信小程序并不反对 Cookies
限度如上所列,但不限于所列。
因为 SameSite 属性存在以上限度,所以须要服务器端仍然采纳 token 机制来避免 CSRF 攻打。
显示指定 SameSite 属性值为 Lax
或Strict
总应该设置一个显式的 SameSite
属性,而不是依赖浏览器为您利用的默认设置。这使您对 Cookie 的应用用意更加明确,并进步了跨浏览器取得统一体验的机会。
不兼容的客户端的解决
对于 SameSite
属性的兼容性在不同浏览器和雷同浏览器的不同版本之间是不同的,能够参考 chromium.org 上的更新页面的已知的不兼容客户端以理解以后已知的问题,然而无奈确定是否详尽无遗。只管这不是现实的抉择,但能够在此过渡阶段中采纳一些解决办法。
形式一:同时设置兼容 SameSite 属性的客户端和不兼容 SameSite 属性的客户端
// ~ 同时设置兼容 SameSite 属性的客户端和不兼容 SameSite 属性的客户端
// ~ 对于兼容 SameSite 属性的客户端,显示指定 SameSite 属性值以明确应用用意
Set-cookie: 3pcookie=value; SameSite=None; Secure
// ~ 对于不兼容 SameSite 属性的客户端,不设置 SameSite 属性
Set-cookie: 3pcookie-legacy=value; Secure
上面的示例显示了如何应用 Express 框架及其 cookie-parser 中间件在 Node.js 中执行此操作。
const express = require('express');
const cp = require('cookie-parser');
const app = express();
app.use(cp());
app.get('/set', (req, res) => {
// Set the new style cookie
res.cookie('3pcookie', 'value', { sameSite: 'none', secure: true});
// And set the same value in the legacy cookie
res.cookie('3pcookie-legacy', 'value', { secure: true});
res.end();});
app.get('/', (req, res) => {
let cookieVal = null;
if (req.cookies['3pcookie']) {
// check the new style cookie first
cookieVal = req.cookies['3pcookie'];
} else if (req.cookies['3pcookie-legacy']) {
// otherwise fall back to the legacy cookie
cookieVal = req.cookies['3pcookie-legacy'];
}
res.end();});
app.listen(process.env.PORT);
形式二:判断客户端的user-agent
在发送 Set-Cookie
相应头时,您能够抉择通过 user-agent
字符串检测客户端。请参阅不兼容客户端的列表,建议您找一个工具库来解决user-agent
,因为您很可能不想本人编写这些正则表达式。
这种办法的益处在于,它只须要在设置 cookie 时进行一次更改即可。然而,此处必须指出是 user-agent
嗅探自身是不牢靠的,并且可能无奈捕捉所有受影响的用户。
无论抉择哪种形式,倡议确保有一种记录低版本客户端比例的办法。一旦比例降落到网站可承受的阈值以下,请确保您有揭示或警报以删除此代替办法。
谷歌打算推出 ”Privacy Sandbox”
谷歌打算齐全禁止第三方 cookie,毕竟 cookie 真的不是很平安,具体参考 this
参考链接
- SameSite cookies explained
- SameSite cookies recipes
- Schemeful Same-Site
- Cookie 的 SameSite 属性 – 阮一峰的网络日志
文章同步公布在各大支流常识共享平台,所以设 github
为对立的反馈区
疑难、探讨、问题反馈:https://github.com/weixsun/di…
关注微信公众号 obmq 及时理解最新动静