返回文章列表

与跨站的 iframe 共享 cookie

先说背景:我们有一个老项目,已经有非常多的模块了,且技术栈比较老旧,维护起来很困难。

所以我打算把一部分老项目的页面迁移到新项目里去写。再通过 iframe 的方式集成在一起。

了解到该项目是后台系统,不对外开放。所以对安全性要求不是非常高,我在引入 iframe 时直接把 token 放到 src 里做 querystring。然后新项目从 url 里拿到 token,再存储到 cookie 里。这样就实现了登录状态的同步。

遇到的问题

但随着新项目部署到测试环境我发现新项目的接口请求都没有通过鉴权。

这个项目的鉴权是基于 cookie 的,而 iframe 里发的请求都没携带 cookie。

排查过程

因为跨站了,因为第三方 Cookie 的禁用,所以 iframe 里面的页面无法读写 cookie。

解决方案

不让带 cookie 但是可以在请求头里自定义其他字段。

我在请求头里添加了一个自定义字段,然后在 nginx 转发的时候把字段名改成 Cookie,实现身份伪装达成登录状态同步。

但感觉方案不是特别好。

部署到同一个顶级域名下就算同站,浏览器默认情况下 Cookie 的 SameSiteLax(下文有解释),所以 iframe 里的页面可以写入 cookie。

资料分享

翻译总结一下外网资料:

写入第三方 cookie 正确的方式如下:

Set-Cookie: session=your_session; SameSite=None; Secure

原理

Cookie 的 domain 和网站的 domain 一致称为第一方 Cookie,不一致称为第三方 Cookie。长期以来二者作用相同,发请求时都会被携带。但这样有一些缺点:

所以后来 Cookie 被添加了一个新的属性,SameSite,此属性允许您声明您的 cookie 是否应限制在第一方或同站上下文中。可能的值:

None: Cookie 也会在第三方上下文中发送。

Strict:只有在第一方上下文中(当浏览器 URL 栏中的域名与您的 cookie 域名匹配时)才会发送 cookie。

Lax: cookie 将在第一方上下文中发送,并且也会随顶级导航一起发送。

浏览器的默认行为发生改变,过去默认值是 None,现在是 Lax,如果想设定为 None 还需要在安全的上下文中。即 https

除此之外还需要 set-cookie 时设定 Secure 属性,即限制必须是 https 协议下传输。

Why not

  1. 为什么不在新项目里自己发请求获取 token 再 set-cookie?因为这样会导致老项目登录状态被挤掉。

  2. 为什么不同源部署?因为人比代码复杂,沟通成本比较高。

  3. 为什么不用下文的正确方式?因为部署到同一个顶级域名下不需要改代码。

后记

英语就是另一门编程语言”

​ ——程序员修炼之道:通向务实的最高境界(第2版)

有时候因为沟通不顺畅,导致自己想了很多奇技淫巧来试图解决问题。

就算可能暂时行得通但因为不是正确方案,心里还是会惴惴不安。所以不可以只顾着低头写代码啊。