lmk123 / blog

个人技术博客,博文写在 Issues 里。
https://github.com/lmk123/blog/issues
623 stars 35 forks source link

更换域名的后续问题:SameSite #101

Open lmk123 opened 2 years ago

lmk123 commented 2 years ago

经过一番折腾,我终于将划词翻译的网站从 hcfy.limingkai.cn 迁移到 hcfy.app 了,本来以为万事大吉了,但测试的时候又发现了一个问题:跨站请求没有携带 cookie,但是在迁移前是正常携带了 cookie 的。

先说一下背景:用户在划词翻译内登录之后,会有一个 cookie 被写进浏览器,cookie 的域跟接口地址是同一个:hs-api.limingkai.cn。然后,hcfy.limingkai.cn 会通过接口获取用户的信息,在请求接口的时候,浏览器会自动带上 cookie,从而实现了用户认证。

但是,当我把网站地址从 hcfy.limingkai.cn 迁移到 hcfy.app 之后,这个 cookie 没有被浏览器携带上去。

我首先确认了调用 fetch() 时正确设置了 credentials: 'include',然后确认在浏览器地址栏里直接打开 hs-api.limingkai.cn 的时候,通过 Chrome Dev Tool 是能看到 cookie 的。这两点都确认无误后,我想到了 SameSite,但是又很疑惑——在迁移前是正常的,应该不会是 SameSite 的问题吧?但现在除了 SameSite 好像也没有别的原因了。

在查阅了相关的文档之后,我知道原因了。

Chrome 默认将 cookie 的 SameSite 设置为了 Lax,即允许同站之间携带跨域 cookie。这个“同站”的概念跟“同源”是不一样的,而这正是此次问题出现的原因:hcfy.limingkai.cn 跟 hs-api.limingkai.cn 是“同站”的,因为它们都有同一个顶级域名 limingkai.cn,但是 hcfy.app 跟 hs-api.limingkai.cn 不是同站的。

这就是迁移前 cookie 能正确携带但迁移后不能的原因。

知道原因了,接下来要想解决方案了。

确保网站跟接口地址“同站”——将 hs-api.limingkai.cn 迁移到 api.hcfy.app

这是我很想做的一件事情,因为既然划词翻译有自己独立的域名了,那么 API 接口地址也应该挂在独立域名下面,但是有两个问题:

更新:迁移失败,未备案的域名 DNS 指向国内服务器是无法访问的。见 #102

修改 SameSite 为 None

当我在 Chrome Dev Tool 将 cookie 的 SameSite 改为 None 之后就能正常携带用户的登录 cookie 了。所以,我只需要在用户登录时给 cookie 多加一个 SameSite=None 就好。

但我遇到了两个问题:

不要用 cookie 作认证

解决这个问题还有一个办法就是不要把 session id 写进 cookie,而是直接返回给客户端 js 保存下来,然后每次请求接口的时候就带上。

这样做的好处是:

但坏处是:

结论

能最快速解决问题的办法是给目前的 cookie 加上 SameSite=None。这应该不难做到,理论上只需要在 Node.js 发送响应前检查一下有没有设置 session id,有的话就补上 SameSite 即可—— Koajs 的洋葱模型好像可以派上用场了。

但综合来看,还是把 hs-api.limingkai.cn 迁移到 api.hcfy.app 更好:扩展程序和网站能共享登录状态、不用加 CRSF Token、划词翻译的接口地址跟 limingka.cn 彻底脱钩。

查阅过的文章: