平台一直使用一套騷操作來完成了單點登錄,主要利用跨域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啦!
最后:
很顯然,我們不能要求客戶來干這種事情。
所以結局是准備重新弄一下單點登錄;