谷歌浏览器新版本Chrome 80默认SameSite导致跨域登录状态失效的问题

年前解决了用corsheaders的方法解决Django跨域问题。但是Django后台发送给chrome浏览器的response header中set-session中默认加上了SameSite=Lax。这个属性禁止第三方请求携带cookie,导致chrom浏览器request请求不能携带cookie。当时在Django setting.py中添加以下设置,禁用chrom中的SamSite属性或者说Django 返回的response header中set-session中SameSite=None

# 会话cookie上SameSite标志的值。此标志防止在跨站点请求中发送cookie,从而防止CSRF攻击,并使某些窃取会话cookie的方法不可能实现。
SESSION_COOKIE_SAMESITE = None  # response header set-cookie:samesite=lax  Default: 'Lax'
CSRF_COOKIE_SAMESITE = None

年后,chrome浏览器更新为chrome 80版本,当还是以上设置时,chrome浏览器默认SamSite=Lax,不能为None。也就是说不设置SameSite时,SameSite默认为Lax.

以下是摘录随风丶逆风 的博客,

定位问题

生产环境出了问题,肯定得赶紧寻找问题根源啊。(三步走路子)

第一步,最先以为cookie失效的问题,于是远程用户,发现浏览器cookie设置正常,域名下cookie也有值,但就是带不过去后台,于是开始怀疑跨域出了问题。
第二步,遂检查Nignx配置,CORS配置正常,那就不是后台的问题,应该是浏览器的锅。
第三步,顺着这条路子,最后发现是Chrome 80版本的一个新特性搞的鬼。
在Chrome 80版本中,Chrome会将没有声明SameSite值的cookie默认设置为SameSite=Lax。只有采用SameSite=None; Secure设置的cookie可以从外部访问,前提是通过安全连接(即HTTPS)访问。
SameSite又是个啥?(T︵T,为啥那么多我不知道的东西),哎,慢慢道来。

什么是SameSite

SameSite是Cookie中的一个属性,它用来标明这个 cookie 是个“同站 cookie”,“同站 cookie” 只能作为第一方cookie,不能作为第三方cookie,因此可以限制第三方Cookie,解决CSRF的问题。不知道CSRF的看着这个。早在Chrome 51中就引入了这一属性,但是不会默认设置,所以相安无事。

第三方Cookie:由当前a.com页面发起的请求的 URL 不一定也是 a.com 上的,可能有 b.com 的,也可能有 c.com 的。我们把发送给 a.com 上的请求叫做第一方请求(first-party request),发送给 b.com 和 c.com 等的请求叫做第三方请求(third-party request),第三方请求和第一方请求一样,都会带上各自域名下的 cookie,所以就有了第一方cookie(first-party cookie)和第三方cookie(third-party cookie)的区别。上面提到的 CSRF 攻击,就是利用了第三方 cookie可以携带发送的特点 。
“同站cookie”不是根据同源策略判断,而是PSL(公共后缀列表),子域名可以访问父域名cookie,但父域名无法访问子域名cookie。

SameSite总共有三个值:Strict、Lax、None。以下内容引自阮一峰博客

Strict
Strict最为严格,完全禁止第三方 Cookie,跨站点时,任何情况下都不会发送 Cookie。换言之,只有当前网页的 URL 与请求目标一致,才会带上 Cookie。

Set-Cookie: CookieName=CookieValue; SameSite=Strict;
1
这个规则过于严格,可能造成非常不好的用户体验。比如像本人当前遇到的现象,cookie带不过,等于一直没有登录状态,就会回到登录页。

Lax
Lax规则稍稍放宽,大多数情况也是不发送第三方 Cookie,但是导航到目标网址的 Get 请求除外。Chrome 80之后默认设置为该值。

Set-Cookie: CookieName=CookieValue; SameSite=Lax;
1
导航到目标网址的 GET 请求,只包括三种情况:链接,预加载请求,GET 表单。详见下表。

请求类型    示例    正常情况    Lax
链接        发送 Cookie    发送 Cookie
预加载        发送 Cookie    发送 Cookie
GET 表单    

    发送 Cookie    发送 Cookie
POST 表单        发送 Cookie    不发送
iframe        发送 Cookie    不发送
AJAX    $.get("…")    发送 Cookie    不发送
Image        发送 Cookie    不发送
设置了Strict或Lax以后,基本就杜绝了CSRF攻击。当然,前提是用户浏览器支持 SameSite 属性。

None
浏览器会在同站请求、跨站请求下继续发送cookies,不区分大小写。网站可以选择显式关闭 SameSite 属性,将其设为 None ,同时必须设置 Secure 属性(表示Cookie 只能通过 HTTPS 协议发送,HTTP协议不会发送),否则无效。

下面为无效响应头:

Set-Cookie: widget_session=abc123; SameSite=None
1
下面为有效响应头:

Set-Cookie: widget_session=abc123; SameSite=None; Secure
1
解决办法

本人项目中,采用统一登录页,存在跨域,采用JSONP的方式获取JWT和域名等相关信息,然后写入指定Domain下的cookie中,满足Lax属性值表单中的AJAX请求,所以不会发送Cookie。

准确定位到问题,就好办了。这里找到了两种解决方法:

显示关闭SameSite属性,按照上述有效响应头设置Ningx的配置文件即可(本人采取的该方法)

浏览器显式关闭该功能。(不推荐,这个功能还是蛮有用的)

地址栏输入:chrome://flags/
找到SameSite by default cookies和Cookies without SameSite must be secure
将上面两项设置为 Disable
参考

https://blog.csdn.net/sinat_36521655/article/details/104844667

https://blog.csdn.net/weixin_42681866/article/details/104786293

http://www.ruanyifeng.com/blog/2019/09/cookie-samesite.html

https://www.ithome.com/0/471/735.htm

https://blog.chromium.org/2019/10/developers-get-ready-for-new.html

https://code.djangoproject.com/ticket/30862

你可能感兴趣的:(Django)