栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > Web开发 > JavaScript

cookie小知识

JavaScript 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

cookie小知识

cookie小知识 http请求携带cookie必须满足下面几个条件

拿一个Http POST请求来说 http://aaa.www.com/xxxxx/list

  1. 浏览器端某个cookie的domain字段等于http://aaa.www.com或者http://www.com (在同一个域内)
  2. 都是http或者https,或者不同的情况下Secure属性为false
  3. 要发送请求的路径,即上面的xxxxx跟浏览器端cookie的path属性必须一致,或者是浏览器端cookie的path的子目录,比如浏览器端cookie的path为/test,那么xxxxxxx必须为/test或者/test/xxxx等子目录(如果cookie设置在http://www.com/list中,那么请求http://aaa.www.com/xxxxx/list可以携带)
SameSite小知识

如果你最近有关注过chrome的控制台,可能会发现经常报一些warning:

A cookie associated with a cross-site resource at http://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.

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

在介绍SameSite属性之前,我们先来复习一下cookie的基础知识

cookie基础

cookie常见的属性:

Name: cookie名。

Value: cookie值。

Domain: cookie的域。如果设成.deepred.com,那么a.deepred.com和b.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了。

cookie携带的场景

我们假设有一个名字为sessionId的cookie,domain设置成了.demo.com。

1.在a.demo.com域名下,ajax在该域名下的所有请求,都会自动带上sessionId

ajax.get('/api/data') // 自动带上sessionId

2.在b.demo.com域名下,ajax在该域名下的所有请求,都会自动带上sessionId

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因为跨站而导致丢失!


跨站解释

http://a.demo.com和http://b.demo.com属于同站,http://a.demo.com和http://a.demo2.com属于跨站

注意和跨域做比较: http://a.demo.com和http://b.demo.com属于跨域

SameSite

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

SameSite可以有下面三种值:

  1. Strict仅允许一方请求携带cookie,即浏览器将只发送相同站点请求的cookie,即当前网页URL与请求目标URL完全一致。
  2. Lax允许部分第三方请求携带cookie
  3. None无论是否跨站都会发送cookie
请求类型 示例 正常情况 Lax
链接 发送 cookie 发送 cookie
预加载 发送 cookie 发送 cookie
GET 表单
发送 cookie 发送 cookie
POST 表单 发送 cookie 不发送
iframe 发送 cookie 不发送
AJAX $.get("...") 发送 cookie 不发送
Image 发送 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

同站和同源 同源

具有相同协议,主机名和端口的组合的网站被视为 相同来源 。其他所有内容均视为 跨域

像 .com 和 .org 这样的顶级域名( tld )会在根区域 数据库 中被列出。在上面的示例中, site 是 TLD 和它前面的部分域的组合。例如,给定一个URL https://www.example.com:443/foo , site 就是 example.com 。

然而,对于 .co.jp 或 .github 这样的域名。仅仅使用 .jp 或 .io 的 TLD 是不够细粒度的。而且也没有办法通过算法确定特定 TLD 的可注册域名级别。这就是创建“有效顶级域名”列表的原因。它们在公共后缀列表中定义。 etld 列表在 publicsuffix.org/list 上维护。

整个站点命名为 eTLD + 1 。例如,假定 URL 为 https://my-project.github.io ,则 eTLD 为 .github.io ,而 eTLD + 1 为 my-project.github.io ,这被视为 site 。换句话说, eTLD+1 是有效的 TLD 紧接其之前的域的一部分。


同站(same-site) 和 跨站(cross-site)

具有相同 eTLD+1 的网站被视为 “同站”。具有不同 eTLD+1 的网站是 “跨站”。

schemeful same-site

尽管 “同站” 忽略了协议(“无协议的同站”),但在某些情况下,必须严格区分协议,以防止 HTTP 被用作弱通道。在这些情况下,一些文档将 “同站” 更明确地称为 schemeful same-site 。在这种情况下, http://www.example.com 和 https://www.example.com 被认为是跨站点的,因为协议不匹配。

如何检查请求是否为 “同站”,“同源”,或“跨站”

Chrome 发送请求时会附带一个   Sec-Fetch-Site HTTP Header 。截至2020年4月,还没有其他浏览器支持 Sec-Fetch-Site ,这个 HTTP Header 将有以下值之一:

  • cross-site

  • same-site

  • same-origin

  • none

通过检查 Sec-Fetch-Site 的值,您可以确定请求是 “同站”,“同源” 还是 “跨站”。

转载请注明:文章转载自 www.mshxw.com
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号