如果你对`samesite`已经有所了解,只是想迅速查看一下几个可选值的含义,可以直接往后翻。
samesite属性的含义
samesite
表示是否允许跨站请求时携带Cookie。 也可以换一句话解释,samesite
表示是否允许当前Cookie作为第三方Cookie被发送到服务端。 举一个实际一点的例子来解释: 银行网站在浏览器端种了一个用于身份认证的Cookie,钓鱼网站在浏览器端给银行网站的服务端发请求时,能否带上这个Cookie,这由该Cookie的samesite
属性决定。
samesite
属性和值都不区分大小写。 samesite
属性可以有如下值:strict
、lax
、none
名词解释
第三方Cookie
所谓第三方Cookie,通用定义是这样的: 浏览器当前访问的网站是第一方。 用户是第二方。 网站在浏览器中向其他Http服务发出请求,这个Http服务就是第三方。
如何判断是否是"其他服务""其他站点",请看下面的"相同站点的判断规则"。
相同站点的判断规则
如何判定两个网站是否是同一个网站? 例如:a.itthink.tech
和b.itthink.tech
是同一个网站吗?
规则是这样的,一般情况下,当两个网站URL中域名的公共后缀
相同,且公共后缀
前面的那一级域名也相同时,那就认为是同一个网站。
什么是公共后缀
? com
和org
、net
、tech
都是公共后缀。但是远不止这些,已知的公共后缀在这里:publicsuffix.org/list/public... 这里要注意的是,github.io
也是公共的后缀,因为a.github.io
和b.github.io
分别代表完全不同的项目主页。a项目和b项目毫不相干,但是它们都共享github.io
域名,因此github.io
这种知名站点就成了公共后缀,因此a.github.io
和b.github.io
被samesite
规则认为是不同的网站。
很显然具有相同公共后缀域名的两个网站不一定是同一个站点,那就继续看公共后缀的下一级。 a.itthink.tech
和b.itthink.tech
的公共后缀都是tech
,tech
的下一级都是itthink
,那samesite
的规则就认为a.itthink.tech
和b.itthink.tech
是同一个网站。
以上便是一些名词和概念解释。 在讲samesite
的各个值之前,我们还需要了解一下CSRF(跨站请求伪造)攻击,这样可以更深刻的理解samesite
。
CSRF(跨站请求伪造)攻击
举例如下: 某银行网站bank.com
在用户登录后会种一个用于身份认证的Cookie。
某钓鱼网站bunk.com
在研究了银行网站转账的Http接口/transfer
后,在钓鱼网站上放了一个表单提交按钮,点击按钮会向该接口提交数据,接口的参数被设置为当前用户账户给钓鱼网站账户转账。
用户登录银行网站bank.com
,并没有登出,而是继续访问了钓鱼网站bunk.com
并点击了其表单提交按钮,此时Cookie会一并被发送到银行服务器,由于有Cookie存在,银行验证通过,钓鱼网站成功将用户的钱转入自己的账户,攻击顺利完成。 以上便是著名的CSRF(跨站请求伪造)攻击。 画图示例如下:
正如我们做了一把枪,本想留给自己人使用的,没曾想被坏人拿过去打我们自己人。我们不能阻止别人拿枪,但是我们可以给子弹加点智能,当它发现当前使用枪的人不是自己人时,子弹就发不出去。这个子弹就是Cookie。
有了以上这些知识后,咱们就可以理解samesite
具体的值了。
可选值"strict"
为了避免CSRF攻击,最有效的方法就是禁止在跨站请求中携带Cookie。 samesite=strict
可以全面的防止跨站请求携带Cookie。 具体包括下面两种情况:
- Cookie只有在所属的网站发请求时才能被带上,从其他网站的页面向Cookie所属网站的服务器发任何请求时,请求中不会有Cookie。
- 从其他网站跳转到Cookie所属的网站时,也不会带上所属网站的Cookie。
这里所说的"请求"均是指从浏览器端向服务器发送的请求。 是否是"其他网站"请参考上面说的"相同站点的判断规则"。
对于情况1我们大部分情况下是可以接受的。 但是对于情况2,可能会影响用户体验。因为根据情况2的规则,从其他网站跳转到我们的网站时,我们预存在浏览器中的Cookie是不会被发送的。如果我们的网站根据Cookie来做出反应的话,那将会导致网站返回的内容和用户的期望不一致。例如用户已经登录过了,但是从其他网站跳转过来时,由于服务端接收不到Cookie,还会要求用户重新登录。
之所以会有情况2这种苛刻的限制也是有原因的。因为攻击者可以在跳转的URL中伪造参数,从而在用户点击链接跳转时对其进行攻击。
但是这确实会一定程度上影响用户体验。
这时我们还有其他选择,请往下看。
可选值"lax"
lax
值也是不允许跨站请求时携带Cookie。但是它有两个例外。
- 浏览器地址跳转到Cookie所属网站且是
GET
请求时,会带上Cookie。 <link rel="prerender">
标签对即将要跳转的网页发送请求进行预渲染时,会带上Cookie。 放宽了这两个限制,我们的用户体验会比"strict"好一些。但是我们一定要确保GET
类的请求都是安全的,幂等的,否则将是一个大漏洞。
我们前后端分离的站点,前端域名有可能会和数据接口的域名属于不同站点(不同站点的规则请看上面的名词解释),假设后端接口有种Cookie的需求,那这种情况下,用strict
和lax
值都会有很大的问题,因为这属于跨站请求中携带Cookie的情况,Cookie会被禁止发送。
samesite
属性还提供了第三个值none
来应对这种情况,这是samesite
最宽松的设置,就和不支持samesite
属性的浏览器行为一样。
可选值"none"
对跨站请求是否可以携带Cookie没有限制。 鉴于该属性过于宽松,IETF后来在一个渐进式改善Cookie的提案中提出当使用samesite=none
时,Cookie必须有secure
属性,否则整个Cookie的设置无效。这里就不列出各个浏览器具体哪个版本开始这么做了,大家就记住加上secure
就可以了。 secure
属性规定Cookie只能在Https请求中被发送,甚至只能在Https请求中被种下。
对于前后端分离的场景,如果前后端域名不属于同一站点,那就只能设置成none
了。不过这种情况下,如果希望Ajax
或者fetch
请求携带Cookie,还需要加上以下配置:
- 浏览器端:给
XMLHttpRequest
的对象加上withCredentials=true
属性,Fetch
也需要相应的withCredentials
相关配置,其配置更为细腻,这里就不多说了。 - 服务端:后端数据服务需加上
Access-Control-Allow-Credentials
响应头。 否则Cookie仍然无法发送。
none
值还有一个巨大的问题,就是某些浏览器的版本对该属性的支持不好,有可能会导致整个Cookie的设置无效。这确实是一个非常头疼的问题。现阶段我们可以像这样去设置Cookie,以便避免这样的问题: Http端:
ini
Set-cookie: 3pcookie=value; SameSite=None; Secure
Set-cookie: 3pcookie-legacy=value; Secure
Javascript端:
ini
// 新样式的Cookie
document.cookie = '3pcookie=value; SameSite=None; Secure';
// 旧样式的Cookie
document.cookie = '3pcookie-legacy=value; Secure';
以上建议来自于谷歌的开发者网站web.dev/samesite-co... 注意SameSite=None; Secure
大小写均可,如果你们团队有代码规范,那就按照规范写。 在获取Cookie时,可以先检查新样式的Cookie是否存在,如果不存在再检查旧样式的。
不得不说这对于我们开发者来说又是一个新噩耗。建议公司团队对Cookie的操作进行封装,然后统一升级。
samesite
的三个可选值均已讲完。 如果我们不设置samesite
,它的默认值是什么呢?请往下看。
samesite的默认值
起初samesite
的默认值是none
,毕竟只有这样才能做到最好的向后兼容。 但是这一情况正在从19年开始慢慢改变,新的默认值将是samesite=lax
。
过渡方案:两分钟内非安刷新跳转请求可带Cookie
所谓刷新跳转请求,也可以叫顶层导航请求,就是说浏览器地址栏会变,浏览器会刷新的Http请求。
在变成lax
之前,有临时过渡方案来给开发人员一定的时间逐步完善Cookie设置。 在过渡方案中,samesite
没有显式设置时,浏览器的大部分行为会和lax
相同,但是允许Cookie被种下的两分钟内,浏览器刷新跳转时,使用非安全的Http method发请求时也能带上Cookie(前提是Cookie的domain
和请求的URL域名匹配)。 举例如下: 当用户访问a.com
网站时,请求itthink.tech
服务种下Cookie:t=xyz; domain=itthink.tech; path=/
,然后用户在两分钟内点击表单提交按钮,表单的method="POST"
,action="https://www.itthink.tech/login"
,在samesite
的默认值临时方案中,虽然a.com
和itthink.tech
是完全不同的站点,且是非安全的POST
请求,但是这个表单请求依然可以带上Cookie:t=xyz
。 这种跨站提交其实有一定的CSRF(跨站请求伪造)风险,但是为了让开发人员有时间逐步完善Cookie设置,这种临时方案有一定的必要性。
虽然现在有临时方案,但是最终肯定是会将默认值彻底变成lax
。因此大家从现在开始就可以给samesite
加上明确的值了,如果拖下去,后续会面临各个不同厂家和版本的浏览器的不同表现,到时候就比较挠头了。
另外Safari和Firefox这些浏览器都在逐步杜绝第三方Cookie,在禁用第三方Cookie的情况下,samesite
其实用处已经不是很大了。但是Chrome到目前为止其第三方Cookie还是放开的状态,而Chrome是当今全球市场份额占比最高的浏览器,因此samesite
对于Cookie安全还是挺重要的。
samesite的意义
优点:samesite
确实对防范CSRF(跨站请求伪造)有很好的作用,虽然目前还没有成为正式标准,但是标准已经在路上了,也被各大浏览器厂商广为接受,广泛实现。
缺点:samesite
并不能防止隐私泄漏,也不能防止Cookie被盗取。Cookie相关的安全和隐私泄漏问题还有很多。
此篇结束。