最近在使用前后端分離開發的時候,遇到了一個詭異的問題,無論如何設置跨域,同一個頁面獲取到的session始終不一致。
發現問題:
- 登錄界面前后端分離,ajax提交登錄時出錯。
- 驗證碼接口和登錄接口的session不一致(跨域問題);
- 在網上搜索跨域問題,重新設置,問題依舊。
錯因排除:
- ajax允許cookie(已經設置 xhrFields: { withCredentials: true} )。
- springboot嘗試設置了多種跨域方法(springboot解決跨域)。
深入分析:
- 使用其它瀏覽器(firefox, ie),session卻是一致的。。
- 對比chrome和firefox請求頭和響應頭:
firefox:首次發起請求后,服務端返回sessionId后,之后每次請求中的cookie都會帶上sessionId。
chrome:請求頭始終未攜帶sessionId,甚至整個cookie都為空,導致服務器每次都接受不到sessionId,每次都會重新分 配 一 個 session。
出現轉機:
搜索chrome未攜帶cookie原因,發現cookie新屬性:SameSite(chrome77版本后支持) 。對該屬性的介紹可以參考這篇文章:SameSite。同時,查看chrome的cookie,由於沒有指明SameSite的取值,chrome默認將其設置為了Lax:
看到其中的一條解決方案: 禁用chrome samesite。方法如下:
1. 在chrome中打開鏈接: chrome://flags/#site-isolation-trial-opt-out,搜索samesite
2.將上述三個選項禁用(設為disable)后重啟chrome,問題解決。
總結:
存在即合理,SameSite的設計初衷是為了防止CSRF攻擊,禁用SameSite實際上並沒有解決問題,屬於下下策。這里提供一下我的理解,SameSite為了防止CSRF攻擊,加強了對cookie的管理,防止用戶帶着cookie去訪問第三方網站,而這又涉及到了跨域問題。然而,我們不可能要求用戶像我們一樣去禁用新版chrome的SameSite,目前的建議就是在header中設置samesite,即上述的response.setHeader("Set-Cookie", "HttpOnly;Secure;SameSite=None")后,使用https傳輸cookie。