若是你最近有關注過chrome的控制檯,可能會發現常常報一些warning:javascript
A cookie associated with a cross-site resource at baidu.com/ was set without the
SameSite
attribute. A future release of Chrome will only deliver cookies with cross-site requests if they are set withSameSite=None
andSecure
.html
出現這個警告的緣由是:chrome在80版本以後,更新了cookies的攜帶機制,把原來Cookie的SameSite
屬性值,由None
改爲了Lax
,這就會致使一些須要第三方cookie的應用產生了異常。java
在介紹SameSite
屬性以前,咱們先來複習一下cookie的基礎知識面試
Cookie常見的屬性:ajax
.deepred.com
,那麼a.deepred.com
和b.deepred.com
域名下,均可以使用.deepred.com
的cookie。/
便可。Session
會話,關閉頁面後,該cookie當即失效。true
後,JS使用document.cookie
則訪問不到。經常使用於避免XSS攻擊。最後一個屬性很是重要,也就是咱們即將要說的SameSite
了。chrome
咱們假設有一個名字爲sessionId
的cookie
,domain
設置成了.demo.com
。segmentfault
1.在a.demo.com
域名下,ajax在該域名下的全部請求,都會自動帶上sessionId
後端
ajax.get('/api/data') // 自動帶上sessionId
複製代碼
2.在b.demo.com
域名下,ajax在該域名下的全部請求,都會自動帶上sessionId
api
ajax.post('/api2/data2') // 自動帶上sessionId
複製代碼
3.在b.demo.com
域名下,ajax請求a.demo.com
的api,須要設置withCredentials
才能帶上sessionId
跨域
ajax.get('https://a.demo.com/api/data') // 不能自動帶上sessionId
ajax.get('https://a.demo.com/api/data', {withCredentials: true}) // 自動帶上sessionId
複製代碼
注意一下: https://a.demo.com/api/data
須要支持cors跨域,而且Access-Control-Allow-Origin
不能設成*
,要設置成https://b.demo.com
,只有這樣,withCredentials
纔有用
router.get('/api/data', (ctx, next) => {
ctx.set('Access-Control-Allow-Origin', ctx.headers.origin);
ctx.set('Access-Control-Allow-Headers', 'Content-Type, Content-Length, Authorization, Accept, X-Requested-With , myheader');
ctx.set('Access-Control-Allow-Methods', 'PUT, POST, GET, DELETE, OPTIONS');
ctx.set('Access-Control-Allow-Credentials', 'true');
};
複製代碼
4.在b.demo.com
域名下,使用iframe
加載a.demo.com
,會自動帶上sessionId
a.demo.com
和b.demo.com
同屬一個域名下的子域名(同站)
5.在a.demo2.com
域名下,ajax請求a.demo.com
的api,須要設置withCredentials
才能帶上sessionId
ajax.get('https://a.demo.com/api/data') // 不能自動帶上sessionId
ajax.get('https://a.demo.com/api/data', {withCredentials: true}) // 自動帶上sessionId
複製代碼
6.在a.demo2.com
域名下,使用iframe
加載a.demo.com
,會自動帶上sessionId
a.demo.com
和a.demo2.com
屬於徹底不相干的兩個網站(跨站)
目前爲止,都是咱們所熟知的cookie攜帶場景。
然而,在chrome 80版本以後,谷歌把cookie的SameSite
屬性,從None
改爲了Lax
。這時候,會致使第5和第6種場景,因爲跨站致使sessionId
丟失!
跨站解釋
a.demo.com
和b.demo.com
屬於同站,a.demo.com
和a.demo2.com
屬於跨站
注意和跨域
作比較: a.demo.com
和b.demo.com
屬於跨域
cookie的SameSite
屬性用來限制第三方Cookie,從而減小安全風險(防止CSRF)
SameSite
能夠有下面三種值:
Strict
僅容許一方請求攜帶Cookie,即瀏覽器將只發送相同站點請求的Cookie,即當前網頁URL與請求目標URL徹底一致。Lax
容許部分第三方請求攜帶CookieNone
不管是否跨站都會發送Cookie從上圖能夠看出,SameSite
從None
改爲了Lax
後,Form
,Iframe
,Ajax
和Image
中跨站的請求受到的影響最大。
解決方法也很簡單粗暴:強行把SameSite
設置成None
。不過須要特別注意幾點:
1.SameSite
設置成None
後,Cookie就必須同時加上Secure
屬性
ctx.cookies.set('sessionId', {
maxAge: 1000 * 60 * 60,
secure: true,
sameSite: 'none',
});
複製代碼
這也意味着,你的網站須要支持https
!(Lax
和Strict
不須要支持https)
若是線上的網站同時支持http
和https
,你可能須要讓運維將http
強制重定向到https
(建議使用307狀態碼而不是302狀態碼)
2.部分瀏覽器不能加SameSite=none
,好比IOS 12的Safari,以及一些老版本的chrome瀏覽器,它們會錯誤的把SameSite=none
識別成SameSite=strict
。
具體不兼容的瀏覽器能夠見這裏
所以後端要根據UA
來判斷是否加上SameSite=none