SameSite小識

若是你最近有關注過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 with SameSite=None and Secure.html

出現這個警告的緣由是:chrome在80版本以後,更新了cookies的攜帶機制,把原來Cookie的SameSite屬性值,由None改爲了Lax,這就會致使一些須要第三方cookie的應用產生了異常。java

在介紹SameSite屬性以前,咱們先來複習一下cookie的基礎知識面試

Cookie基礎

Cookie常見的屬性:ajax

  • Name: cookie名。
  • Value: cookie值。
  • Domain: cookie的域。若是設成.deepred.com,那麼a.deepred.comb.deepred.com域名下,均可以使用.deepred.com的cookie。
  • Path: cookie的路徑。請求資源的路徑必定要包含這個path才能攜帶cookie。通常設置成/便可。
  • Expires/Max-Age: cookie過時時間。默認不設置,則是Session會話,關閉頁面後,該cookie當即失效。
  • HttpOnly: 設成true後,JS使用document.cookie則訪問不到。經常使用於避免XSS攻擊。
  • Secure: 標記爲Secure的cookie只應經過被HTTPS協議加密過的請求發送給服務端。
  • SameSite: 用來限制第三方Cookie

最後一個屬性很是重要,也就是咱們即將要說的SameSite了。chrome

Cookie攜帶的場景

咱們假設有一個名字爲sessionIdcookiedomain設置成了.demo.comsegmentfault

1.在a.demo.com域名下,ajax在該域名下的全部請求,都會自動帶上sessionId後端

ajax.get('/api/data') // 自動帶上sessionId
複製代碼

2.在b.demo.com域名下,ajax在該域名下的全部請求,都會自動帶上sessionIdapi

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.comb.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.coma.demo2.com屬於徹底不相干的兩個網站(跨站)

目前爲止,都是咱們所熟知的cookie攜帶場景。

然而,在chrome 80版本以後,谷歌把cookie的SameSite屬性,從None改爲了Lax這時候,會致使第5和第6種場景,因爲跨站致使sessionId丟失!

跨站解釋

a.demo.comb.demo.com屬於同站,a.demo.coma.demo2.com屬於跨站

注意和跨域作比較: a.demo.comb.demo.com屬於跨域

SameSite

cookie的SameSite屬性用來限制第三方Cookie,從而減小安全風險(防止CSRF)

SameSite能夠有下面三種值:

  1. Strict僅容許一方請求攜帶Cookie,即瀏覽器將只發送相同站點請求的Cookie,即當前網頁URL與請求目標URL徹底一致。
  2. Lax容許部分第三方請求攜帶Cookie
  3. None不管是否跨站都會發送Cookie

從上圖能夠看出,SameSiteNone改爲了Lax後,Form,Iframe,AjaxImage跨站的請求受到的影響最大。

解決方法

解決方法也很簡單粗暴:強行把SameSite設置成None。不過須要特別注意幾點:

1.SameSite設置成None後,Cookie就必須同時加上Secure屬性

ctx.cookies.set('sessionId', {
  maxAge: 1000 * 60 * 60,
  secure: true,
  sameSite: 'none',
});
複製代碼

這也意味着,你的網站須要支持https!(LaxStrict不須要支持https)

若是線上的網站同時支持httphttps,你可能須要讓運維將http強制重定向到https(建議使用307狀態碼而不是302狀態碼)

2.部分瀏覽器不能加SameSite=none,好比IOS 12的Safari,以及一些老版本的chrome瀏覽器,它們會錯誤的把SameSite=none識別成SameSite=strict

具體不兼容的瀏覽器能夠見這裏

所以後端要根據UA來判斷是否加上SameSite=none

參考

相關文章
相關標籤/搜索