SameSite小识

若是你最近有关注过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 with SameSite=None and Secure.html

出现这个警告的缘由是:chrome在80版本以后,更新了cookies的携带机制,把原来Cookie的SameSite属性值,由None改为了Lax,这就会致使一些须要第三方cookie的应用产生了异常。java

在介绍SameSite属性以前,咱们先来复习一下cookie的基础知识面试

Cookie基础

Cookie常见的属性:ajax

  • Name: cookie名。
  • Value: cookie值。
  • Domain: cookie的域。若是设成.deepred.com,那么a.deepred.comb.deepred.com域名下,均可以使用.deepred.com的cookie。
  • Path: cookie的路径。请求资源的路径必定要包含这个path才能携带cookie。通常设置成/便可。
  • Expires/Max-Age: cookie过时时间。默认不设置,则是Session会话,关闭页面后,该cookie当即失效。
  • HttpOnly: 设成true后,JS使用document.cookie则访问不到。经常使用于避免XSS攻击。
  • Secure: 标记为Secure的cookie只应经过被HTTPS协议加密过的请求发送给服务端。
  • SameSite: 用来限制第三方Cookie

最后一个属性很是重要,也就是咱们即将要说的SameSite了。chrome

Cookie携带的场景

咱们假设有一个名字为sessionIdcookiedomain设置成了.demo.comsegmentfault

1.在a.demo.com域名下,ajax在该域名下的全部请求,都会自动带上sessionId后端

ajax.get('/api/data') // 自动带上sessionId
复制代码

2.在b.demo.com域名下,ajax在该域名下的全部请求,都会自动带上sessionIdapi

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.comb.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.coma.demo2.com属于彻底不相干的两个网站(跨站)

目前为止,都是咱们所熟知的cookie携带场景。

然而,在chrome 80版本以后,谷歌把cookie的SameSite属性,从None改为了Lax这时候,会致使第5和第6种场景,因为跨站致使sessionId丢失!

跨站解释

a.demo.comb.demo.com属于同站,a.demo.coma.demo2.com属于跨站

注意和跨域作比较: a.demo.comb.demo.com属于跨域

SameSite

cookie的SameSite属性用来限制第三方Cookie,从而减小安全风险(防止CSRF)

SameSite能够有下面三种值:

  1. Strict仅容许一方请求携带Cookie,即浏览器将只发送相同站点请求的Cookie,即当前网页URL与请求目标URL彻底一致。
  2. Lax容许部分第三方请求携带Cookie
  3. None不管是否跨站都会发送Cookie

从上图能够看出,SameSiteNone改为了Lax后,Form,Iframe,AjaxImage跨站的请求受到的影响最大。

解决方法

解决方法也很简单粗暴:强行把SameSite设置成None。不过须要特别注意几点:

1.SameSite设置成None后,Cookie就必须同时加上Secure属性

ctx.cookies.set('sessionId', {
  maxAge: 1000 * 60 * 60,
  secure: true,
  sameSite: 'none',
});
复制代码

这也意味着,你的网站须要支持https!(LaxStrict不须要支持https)

若是线上的网站同时支持httphttps,你可能须要让运维将http强制重定向到https(建议使用307状态码而不是302状态码)

2.部分浏览器不能加SameSite=none,好比IOS 12的Safari,以及一些老版本的chrome浏览器,它们会错误的把SameSite=none识别成SameSite=strict

具体不兼容的浏览器能够见这里

所以后端要根据UA来判断是否加上SameSite=none

参考

相关文章
相关标签/搜索