若是你最近有关注过chrome的控制台,可能会发现常常报一些warning:javascript
A cookie associated with a cross-site resource at baidu.com/ was set without the
SameSite
attribute. A future release of Chrome will only deliver cookies with cross-site requests if they are set withSameSite=None
andSecure
.html
出现这个警告的缘由是:chrome在80版本以后,更新了cookies的携带机制,把原来Cookie的SameSite
属性值,由None
改为了Lax
,这就会致使一些须要第三方cookie的应用产生了异常。java
在介绍SameSite
属性以前,咱们先来复习一下cookie的基础知识面试
Cookie常见的属性:ajax
.deepred.com
,那么a.deepred.com
和b.deepred.com
域名下,均可以使用.deepred.com
的cookie。/
便可。Session
会话,关闭页面后,该cookie当即失效。true
后,JS使用document.cookie
则访问不到。经常使用于避免XSS攻击。最后一个属性很是重要,也就是咱们即将要说的SameSite
了。chrome
咱们假设有一个名字为sessionId
的cookie
,domain
设置成了.demo.com
。segmentfault
1.在a.demo.com
域名下,ajax在该域名下的全部请求,都会自动带上sessionId
后端
ajax.get('/api/data') // 自动带上sessionId
复制代码
2.在b.demo.com
域名下,ajax在该域名下的全部请求,都会自动带上sessionId
api
ajax.post('/api2/data2') // 自动带上sessionId
复制代码
3.在b.demo.com
域名下,ajax请求a.demo.com
的api,须要设置withCredentials
才能带上sessionId
跨域
ajax.get('https://a.demo.com/api/data') // 不能自动带上sessionId
ajax.get('https://a.demo.com/api/data', {withCredentials: true}) // 自动带上sessionId
复制代码
注意一下: https://a.demo.com/api/data
须要支持cors跨域,而且Access-Control-Allow-Origin
不能设成*
,要设置成https://b.demo.com
,只有这样,withCredentials
才有用
router.get('/api/data', (ctx, next) => {
ctx.set('Access-Control-Allow-Origin', ctx.headers.origin);
ctx.set('Access-Control-Allow-Headers', 'Content-Type, Content-Length, Authorization, Accept, X-Requested-With , myheader');
ctx.set('Access-Control-Allow-Methods', 'PUT, POST, GET, DELETE, OPTIONS');
ctx.set('Access-Control-Allow-Credentials', 'true');
};
复制代码
4.在b.demo.com
域名下,使用iframe
加载a.demo.com
,会自动带上sessionId
a.demo.com
和b.demo.com
同属一个域名下的子域名(同站)
5.在a.demo2.com
域名下,ajax请求a.demo.com
的api,须要设置withCredentials
才能带上sessionId
ajax.get('https://a.demo.com/api/data') // 不能自动带上sessionId
ajax.get('https://a.demo.com/api/data', {withCredentials: true}) // 自动带上sessionId
复制代码
6.在a.demo2.com
域名下,使用iframe
加载a.demo.com
,会自动带上sessionId
a.demo.com
和a.demo2.com
属于彻底不相干的两个网站(跨站)
目前为止,都是咱们所熟知的cookie携带场景。
然而,在chrome 80版本以后,谷歌把cookie的SameSite
属性,从None
改为了Lax
。这时候,会致使第5和第6种场景,因为跨站致使sessionId
丢失!
跨站解释
a.demo.com
和b.demo.com
属于同站,a.demo.com
和a.demo2.com
属于跨站
注意和跨域
作比较: a.demo.com
和b.demo.com
属于跨域
cookie的SameSite
属性用来限制第三方Cookie,从而减小安全风险(防止CSRF)
SameSite
能够有下面三种值:
Strict
仅容许一方请求携带Cookie,即浏览器将只发送相同站点请求的Cookie,即当前网页URL与请求目标URL彻底一致。Lax
容许部分第三方请求携带CookieNone
不管是否跨站都会发送Cookie从上图能够看出,SameSite
从None
改为了Lax
后,Form
,Iframe
,Ajax
和Image
中跨站的请求受到的影响最大。
解决方法也很简单粗暴:强行把SameSite
设置成None
。不过须要特别注意几点:
1.SameSite
设置成None
后,Cookie就必须同时加上Secure
属性
ctx.cookies.set('sessionId', {
maxAge: 1000 * 60 * 60,
secure: true,
sameSite: 'none',
});
复制代码
这也意味着,你的网站须要支持https
!(Lax
和Strict
不须要支持https)
若是线上的网站同时支持http
和https
,你可能须要让运维将http
强制重定向到https
(建议使用307状态码而不是302状态码)
2.部分浏览器不能加SameSite=none
,好比IOS 12的Safari,以及一些老版本的chrome浏览器,它们会错误的把SameSite=none
识别成SameSite=strict
。
具体不兼容的浏览器能够见这里
所以后端要根据UA
来判断是否加上SameSite=none