聊聊Cookie的SameSite属性

背景

前几天在业务开发中,在iframe中嵌入打开一个xxx的url链接,在链接的主页中,会跳转到另一个登录的页面,然而登录一直失败,失败原因是xxx的服务端没有收到对应的cookie。但是在浏览器中的顶层搜索打开xxx的url链接,在跳转到另一个登录的页面后,就可以正常的登录。

页面嵌套关系如下所示:

image.png

Cookie简介:

HTTP 协议是无状态的,但可以通过 Cookie 来维持客户端与服务端之间的“会话状态”。

简单来说就是:服务端通过 Set-Cookie 响应头设置 Cookie 到客户端,而客户端在下次向服务器发送请求时添加名为 Cookie 的请求头,以携带服务端之前“埋下”的内容,从而使得服务端可以识别客户端的身份。

场景模拟

本地代码示例如下:

配置本地host

127.0.0.1 a.cross.com
127.0.0.1 b.test.com
127.0.0.1 a.test.com

开启serverB:

const http = require("http");
const fs = require("fs");

let server = http.createServer((req, res) => {
    const cookie = req.headers.cookie
    console.log('cookie', cookie);
    res.writeHead(200, [
        ["Set-Cookie", "name=bbb"], // 设置 cookie
    ]);

    if (!cookie) {
        res.end("no cookie");//没有cookie时
        return
    }
    if ("/" == req.url) {
        fs.readFile(__dirname + "/index.html", "utf-8", (err, data) => {
            if (err) {
                throw err;
            } else {
                res.end(data);
            }
        });
    } else if (req.url == "/favicon.ico") {
        res.statusCode = 204;
        res.end();
    } else {
        res.end("404 NOT Found");
    }

});
server.listen(3002, () => {
    console.log("服务器启动成功");
});

serverB中index.html的body为:

<body>
    <div>i am B页面</div>
</body>

在浏览器顶部导航栏输入http://b.test.com:3002时,正常的B页面展示为

image.png

在A中使用iframe嵌套B的url,开启serverA:

const http = require("http");
const fs = require("fs");

let server = http.createServer((req, res) => {
    console.log(req.url);
    if ("/" == req.url) {
        fs.readFile(__dirname + "/index.html", "utf-8", (err, data) => {
            if (err) {
                throw err;
            } else {
                res.end(data);
            }
        });
    } else if (req.url == "/favicon.ico") {
        res.statusCode = 204;
        res.end();
    } else {
        res.end("404 NOT Found");
    }

});
server.listen(3001, () => {
    console.log("服务器启动成功");
});

serverA中index.html的body为:

<body>
    <div>i am A页面</div>
    <iframe src="http://b.test.com:3002"></iframe>//iframe嵌套B页面的url
</body>

在chrome中打开http://a.cross.com:3001,页面展示如下:

image.png

可以看到在A页面的iframe中嵌套B页面时,在B服务中没有获取到cookie信息,所以没有展示正常的B页面。

排查问题

那接下来就一块来分析问题吧。

既然在浏览器顶部导航栏输入http://b.test.com:3002时可以正常显示,那看一下此时的网络请求情况:

image.png

看一下访问失败时的请求头情况

image.png

可以看到请求异常的情况下,请求头中没有携带cookie信息,并且在响应头中会提示SameSite=Lax信息。

查看b站点的Application中的Cookie信息

image.png

可以看到本地有b站点的cookie信息。为什么本地有cookie信息,但是请求的时候request header中没有携带此cookie信息呢?

查找资料得知,从 Chrome 80 开始,如果不指定 SameSite 就等效于设置为 Lax

SameSite属性

SameSite 是 HTTP 响应头 Set-Cookie的属性之一。它允许声明该 Cookie 是否仅限于第一方或者同一站点上下文。

SameSite 可以有下面三种值:

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

之前默认是 None 的,Chrome80 后默认是 Lax。

Lax的情况见下表:

请求类型 示例 正常情况 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 不发送
AJAX $.get("...") 发送 Cookie 不发送
Image <img src="..."> 发送 Cookie 不发送

当sameSite为Lax时,post、iframe、ajax、image的跨站请求都不会发送cookie。

要理解上面的规则,还需要了解一下跨域和跨站的区别。

跨域和跨站

首先要理解的一点就是跨站和跨域是不同的。同站(same-site)/跨站(cross-site)和第一方(first-party)/第三方(third-party)是等价的。但是与浏览器同源策略(SOP)中的同源(same-origin)/跨域(cross-origin)是完全不同的概念。

同源策略的同源是指两个 URL 的协议/主机名/端口一致。例如,https://www.baidu.com,它的协议是 https,主机名是 www.baidu.com,端口是 443。

同源策略作为浏览器的安全基石,其同源判断是比较严格的。相对而言,Cookie中的同站判断就比较宽松:只要两个 URL 的 eTLD+1 相同即可,不需要考虑协议和端口。其中,eTLD 表示有效顶级域名,注册于 Mozilla 维护的公共后缀列表(Public Suffix List)中,例如,.com、.co.uk、.github.io 等。eTLD+1 则表示,有效顶级域名+二级域名,例如 baidu.com 等。

举几个例子,www.taobao.comwww.baidu.com 是跨站,a.baidu.comb.baidu.com是同站,a.github.iob.github.io 是跨站(注意是跨站)。

在上面的模拟示例中我使用的chrome浏览器的版本是107版本,虽然本地是有cookie信息,但是SameSite为空,也就是没有设置,所以默认SameSite=Lax,导致在A页面访问iframe中的B站点时,是跨站的方式,不会发送B站点的cookie信息。

解决方案

这种问题的解决方案有以下几种

1、服务器在set-cookie时,设置SameSite=None; Secure。但是这里需要注意:

  • HTTP 接口不支持 SameSite=none。如果你想加 SameSite=none 属性,那么该 Cookie 就必须同时加上 Secure 属性,表示只有在 HTTPS 协议下该 Cookie 才会被发送。
  • 部分浏览器不支持部分SameSite=none。IOS 12 的 Safari 以及老版本的一些 Chrome 会把 SameSite=none 识别成 SameSite=Strict,所以服务端必须在下发 Set-Cookie 响应头时进行 User-Agent 检测,对这些浏览器不下发 SameSite=none 属性。

2、使用Nginx或其他网关工具进行Proxy操作,使跨站请求变为同站请求

将这个被调用接口的应用和发起请求的应用放在同一个站下面,使他们是同站请求,这样就不存在跨站问题了。

比如上面模拟示例所示,在host配置中,将A站点127.0.0.1使用a.test.com映射,这样在a.test.com中访问b.test.com就是同站访问了。

或者使用nginx代理请求,将a.test.com代理到a.cross.com,这样在浏览器中顶部导航栏中输入a.test.com就可以被nginx代理访问到a.cross.com,而这时浏览器会认为在a.test.com页面中访问b.test.com,浏览器会当作同站处理cookie。同理可以使用nginx代理b站点的url,使与A站点同站。

3、使用http auth也就是header auth方式进行,将令牌通过header的形式传输,不使用Cookie,那当然也就不存在Cookie中奇奇怪怪的问题了。

4、使用指定版本的浏览器,使用chrome内核低于80的浏览器,或者在safari中关闭防止跨站追踪选项。

以上列出了4种解决此类问题的方法,具体还需要结合自己的业务场景选择合适的解决方案。

参考:

https://github.com/mqyqingfeng/Blog/issues/157

https://zhuanlan.zhihu.com/p/266282015

https://juejin.cn/post/6963632513914765320#heading-6

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 155,457评论 4 357
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 65,943评论 1 285
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 105,327评论 0 236
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,307评论 0 201
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,630评论 3 283
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,114评论 1 202
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,514评论 2 305
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,227评论 0 193
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 33,859评论 1 234
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,186评论 2 238
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,741评论 1 255
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,087评论 2 248
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,614评论 3 228
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,926评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,630评论 0 190
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,117评论 2 261
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,076评论 2 257

推荐阅读更多精彩内容