平台一直使用一套骚操作来完成了单点登录,主要利用跨域cookie来获取redis中缓存的用户信息来判断是否登录;突然有天失效了,于是有了此文;
平台背景:
- 现有A、B两个平台,A登录后,将用户登录信息放入redis并获取到key,将key存入http://A/user/的Cookie下;
- B平台登录的时候跨域调用http://A/user/auth/acquire请求,此请求会携带这个域下的Cookie
- 后台服务拿到Cookie中的key去reids查询到登录信息,返回登录成功;
- 完成整个的单点登录逻辑;
翻车现场:
- 测试提出单点登录失效,在A平台登录成功后,访问B平台仍然需要登录;
于是开始排查:
- 查看A平台登录后,http://A/user/的Cookie下存在key, 此处没有问题;
- 访问B平台时,B平台调用http://A/user/auth/acquire接口,但是接口缺失Cookie;
。。。。
之前明明是好的!!!
排查
详细查看下请求
发现了一个感叹号,查看内容,发现了SameSite属性,且是因为SameSite=Lax导致无法set-cookie, 通过查询了解一下这个属性;可以看到阮大大的博客有介绍这个属性;
http://www.ruanyifeng.com/blog/2019/09/cookie-samesite.html
以下摘自博客:
Cookie 的SameSite
属性用来限制第三方 Cookie,从而减少安全风险。
它可以设置三个值。
- Strict
- Lax
- None
2.1 Strict
Strict
最为严格,完全禁止第三方 Cookie,跨站点时,任何情况下都不会发送 Cookie。换言之,只有当前网页的 URL 与请求目标一致,才会带上 Cookie。
Set-Cookie: CookieName=CookieValue; SameSite=Strict;
这个规则过于严格,可能造成非常不好的用户体验。比如,当前网页有一个 GitHub 链接,用户点击跳转就不会带有 GitHub 的 Cookie,跳转过去总是未登陆状态。
2.2 Lax
Lax
规则稍稍放宽,大多数情况也是不发送第三方 Cookie,但是导航到目标网址的 Get 请求除外。
Set-Cookie: CookieName=CookieValue; SameSite=Lax;
导航到目标网址的 GET 请求,只包括三种情况:链接,预加载请求,GET 表单。详见下表。
请求类型 | 示例 | 正常情况 | 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 | 不发送 |
设置了Strict
或Lax
以后,基本就杜绝了 CSRF 攻击。当然,前提是用户浏览器支持 SameSite 属性。
2.3 None
Chrome 计划将Lax
变为默认设置。这时,网站可以选择显式关闭SameSite
属性,将其设为None
。不过,前提是必须同时设置Secure
属性(Cookie 只能通过 HTTPS 协议发送),否则无效。
下面的设置无效。
Set-Cookie: widget_session=abc123; SameSite=None
下面的设置有效。
Set-Cookie: widget_session=abc123; SameSite=None; Secure
很显然,Chrome是支持SameSite属性的,且通过资料可以知道在Chrome 80+版本,Chrome还将SameSite默认值改为了Lax,这也是导致此问题的主要原因;
以下是Chrome的特性介绍:
A cookie associated with a cross-site resource at accounts.google.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. You can review cookies in developer tools under Application>Storage>Cookies and see more details at
https://www.chromestatus.com/feature/5088147346030592
andhttps://www.chromestatus.com/feature/5633521622188032
尝试解决:
在Chrome启动命令中,添加--disable-features=SameSiteByDefaultCookies命令,即可关闭SameSite属性,此时问题修复;
步骤如下:
-
找到Chrome目录,新建Chrome的快捷方式
-
右击快捷方式的属性,将属性命令复制到目标栏中
- 保存,关闭Chrome,然后通过新建的快捷方式打开Chrome;
发现已经可以携带Cookie啦!
最后:
很显然,我们不能要求客户来干这种事情。
所以结局是准备重新弄一下单点登录;