chrome80默认SameSite导致iframe无法获取cookie问题解决方法

chrome80默认SameSite导致iframe无法获取cookie问题解决方法

项目背景及问题定位

项目背景

chrome80默认SameSite导致iframe无法获取cookie问题解决方法

A网站(假设为http://SameSite.a.com)作为iframe内嵌在B网站(假设为http://test.a.com)。在B网站中加载A网站的时候,自动登录失效,导致接口一直重调。

问题定位

  • 初步分析,A网站为第三方页面,将A网站直接在外部打开可以单独访问,排除A网站的问题
  • 更换浏览器,在火狐和Edge中,A网站可正常在iframe中加载。初步定位为浏览器兼容问题
  • 对比不能正常加载和正常加载的chrome浏览器版本,都更新到最新的89版本。发现状态没变,能加载的还是能,不行的依然加载不了。(因为这个现象,导致对是否是浏览器版本兼容问题产生了怀疑)
  • 打开浏览器控制台,发现接口请求报错,控制台出现以下提示
    chrome80默认SameSite导致iframe无法获取cookie问题解决方法
    错误与SameSite属性有关系,因此去查了一下SameSite相关的问题。SameSite相关属性可参考阮一峰的《Cookie 的 SameSite 属性

问题出现的原因

Google将在2020年2月4号发布的 Chrome 80 版本(schedule:https://www.chromestatus.com/features/schedule)中默认屏蔽所有第三方 Cookie,即默认为所有 Cookie 加上SameSite=Lax属性(https://www.chromestatus.com/feature/5088147346030592), 并且拒绝非Secure的Cookie设为 SameSite=None (https://www.chromestatus.com/feature/5633521622188032) 此举是为了从源头屏蔽 CSRF 漏洞

以下场景会在Chrome80中受到影响:

  • 组件数据基于第三方登陆态的 API 请求
  • http 本地部署

解决方案

当前项目环境:A网站与B网站主域名保持一致,A网站域名为https。下面方法未奏效可以先考虑一下环境问题

注意事项

  • SameSite=None需要只对chrome80以上版本进行设置,原因在于chrome51-chrome66以及其他某些浏览器不接受SameSite=None
  • 如果网站存在http与https同时使用的情况,需要对此做兼容,只有https的时候才设置Secure;SameSite=None。原因在于当Secure设置为true时,表示创建的 Cookie 会被以安全的形式向服务器传输,也就是只能在 HTTPS 连接中被浏览器传递到服务器端进行会话验证。
  • 根据谷歌文档Reject insecure SameSite=None cookies中所述,85版本后默认启用“拒绝非安全的samesite=none的cookie”这一特性,要同时显式声明secure=true,这个cookie才能跨域携带。

解决方案

    1. Chrome中打开标签页,分别输入以下两个链接,将图示配置设为Disabled。(亲测有效,可以当做应急方案,更新配置后得重启浏览器,才能生效)
chrome://flags/#same-site-by-default-cookies
chrome://flags/#cookies-without-same-site-must-be-secure

chrome80默认SameSite导致iframe无法获取cookie问题解决方法
chrome80默认SameSite导致iframe无法获取cookie问题解决方法

    1. 使用火狐或Edge浏览器(有效)或者将chrome降级到79及以下版本,并关闭自动更新(未试验,个人不推荐,方案用户体验太差)
    1. 将两个系统部署到同一台服务器,通过相同IP同源策略传送cookie。(未试验)
    1. 购买SSL证书,升级HTTP服务,将API切换成HTTPS协议请求,并且检查响应头中的Set-Cookie中是否包含了SameSite=None和Secure属性(85以后版本需显式设置Secure=true)

总结

  • 虽然问题解决了,的确是浏览器版本问题,但是为什么有些电脑能正常加载有些不行,这个还是不清楚原因
  • 本次问题使用的方案四解决了,但是在浏览博文的时候,还是踩了很多坑后才找到了最终的解决方法。
    简单介绍一下方案4实际解决问题的方案:
  1. 如果前端所需cookie是后端直接通过Set-cookie的方式来存在浏览器中的,那么则需要后端在response响应头上设置属性。每个所需要的cookie都得设置一遍。没设置的就会出现图示的黄色标识(提醒你无法成功设置cookie),这种cookie是读取不了的
response.setHeader(name: "Set-Cookie", value: "_u=xxxx; Path=/Login; SameSite=None; Secure=true")

chrome80默认SameSite导致iframe无法获取cookie问题解决方法

  1. 也可以在Nginx中设置,自动给cookie增加这两个属性(给所有cookie都设置这个不是特别安全,不推荐用这个,只给特定的需要的cookie按上面的方案设置一下就行了)
# 只支持 proxy 模式下设置
proxy_cookie_path / "/; httponly; Secure=true; SameSite=None";
  1. 第一个方法只适用于后端设置的cookie,本次遇见的问题中,cookie是前端将后端返回的数据拿到后再存在浏览器中的,导致按照第一种方法一直解决不了问题。如果是前端将cookie存入浏览器中的话,那只需要写入如下代码,即可设置相应cookie的属性,从而解决问题了
Cookies.set("Admin-Token", res.token);
document.cookie = "Admin-Token=" + res.token + ";SameSite=None; Secure=true";

参考文章

阮一峰:《Cookie 的 SameSite 属性
关于 Chrome (谷歌浏览器)升级到 80 后可能产生的影响以及解决方案
浏览器的SameSite策略
chrome浏览器跨域Cookie的SameSite问题导致访问iframe内嵌页面异常

上一篇:独立窗口Cookie 丢失的问题


下一篇:使用libcurl库实现C++程序发送邮件的功能