SameSite - Chrome 80 第三方 Cookie 规则调整
2020-07-08 #Coding

起因

最近在用一个 Chrome 扩展程序时登录相关的一直异常,心想这么大的线上问题都没有监控吗?顺手还是联系了下客服,本来以为收到的会是例行的客服话术,谁知道客服回复还提供了个技术方案:

突然想到 Chrome 80 已经更新了一段时间了,其中关于SameSite的相关默认规则由 none 变为 Lax,一些跨站 cookie 操作默认会被禁止掉。

Chrome 工程总监 Justin Schuh 在 Chromium Blog 发文宣布暂时回滚 SameSite Cookie 功能,以确保新冠病毒疫情期间网站的稳定性。SameSite 是全新的 cookie 分类模型,在二月初发布的 Chrome 80 稳定版中被引入。Chrome 会将没有声明 SameSite 值的 cookie 默认设置为 SameSite=Lax 。

联想到早些时候看到的新闻 谷歌宣布暂时回滚Chrome隐私功能 以确保疫情期间网站稳定性,疫情给开发者了一些冗余处理时间,只是这家公司还是拖到了宽限期结束都没处理,还让用户去关闭相关设置。

碰到了这个事就对 SameSite 相关内容进行一次知识整理:

  • 何为 SameSite
  • 何为 CSRF
  • SameSite 默认规则更新造成的影响
  • Cookie 上的其他属性

何为 SameSite

SameSite是 Cookie 中的一个属性,Chrome 51 开始存在。

MDN描述:允许您声明是否应将Cookie限制为第一方或同一站点上下文,通俗点就是限制第三方 Cookie 使用,跨站请求时阻止Cookie发送,减少 CSRF 等潜在的安全风险。

1
Set-Cookie: cookieKey=cookieValue; SameSite=Strict;

其可以设置为三个值:

  • Strict: 严格模式,完全禁止阻止跨站点使用 Cookie,网站URL和请求目标一致才允许
  • Lax: Chrome 80 之后的默认值,除了<a>, <link rel="prerender">, <form method="GET">以外都的跨站使用 Cookie 都会被阻止
  • None: 以前的默认值,没有限制

Strict

最严格的模式,第三方 Cookie 会被完全禁止,只有当前页面URL和请求目标一致才会带上 Cookie。

缺点是过于严格,体验会比较差,链接跳转都无法携带 Cookie,造成 Session 中等登陆态无法获取,无法保持登陆状态等。

Lax

适当放宽限制的设置,导航到目标URL的GET请求被除外,允许发送第三方 Cookie,包含以下三种情况:

<a>, <link rel="prerender">, <form method="GET">

具体的限制对比表如下:

请求类型 示例 正常情况 Lax None
链接 <a href="..."></a> 发送 Cookie 发送 Cookie 发送 Cookie
预加载 <link rel="prerender" href="..."/> 发送 Cookie 发送 Cookie 发送 Cookie
GET 表单 <form method="GET" action="..."> 发送 Cookie 发送 Cookie 发送 Cookie
POST 表单 <form method="POST" action="..."> 发送 Cookie 不发送 发送 Cookie
iframe <iframe src="..."></iframe> 发送 Cookie 不发送 发送 Cookie
AJAX $.get("...") 发送 Cookie 不发送 发送 Cookie
Image <img src="..."> 发送 Cookie 不发送 发送 Cookie

None

无限制,为网站自主选择显式关闭SameSite属性使用。

前提必须同时设置Secure(Cookie 必须通过 HTTPS 发送)

1
2
3
4
# 无效
Set-Cookie: sessionKey=test123; SameSite=None;
# 有效
Set-Cookie: sessionKey=test123; SameSite=None; Secure

何为 CSRF

英文全名:Cross-site request forgery,跨站请求伪造,缩写也可以为 XSRF,是一种挟制用户在当前已登录的Web应用程序上执行非本意的操作的攻击方法。

跨网站脚本(XSS)相比,XSS 利用的是用户对指定网站的信任,CSRF 利用的是网站对用户网页浏览器的信任。

Cookie 经常用了存储一些重要信息,如用户标识等。其他网站伪造一个请求并携带当前用户已存在的cookie,骗过目标浏览器,执行非用户意愿的操作

这种由第三方网站发出的 Cookie 即为第三方 Cookie

举例

1
2
3
4
5
6
7
// 假如一家银行用以运行转账操作的URL地址如下: 
https://bank.example.com/withdraw?account=AccoutName&amount=1000&for=PayeeName

// 那么,一个恶意攻击者可以在另一个网站上放置如下代码:
<img src="https://bank.example.com/withdraw?account=Alice&amount=1000&for=Badman" />

// 如果有账户名为Alice的用户访问了恶意站点,而她之前刚访问过银行不久,登录信息尚未过期,那么她就会损失1000资金。

防御措施

  • 表单添加来自服务端随机校验 token ,用于验证真实性
  • 检查 HTTP 请求 Header 中的 Referer 字段,排除非安全列表请求

用于用户追踪

广告、站点本身的数据追踪等,在页面有意植入第三方站点中,将第三方站点 Cookie 相关信息发送回,用于数据分析追踪用户行为等。

SameSite 默认规则更新造成的影响

当然不是所有的第三方 Cookie 都是恶意的,有很多情况下一些大型站点拥有大量不同域名的业务,跨站点获取登录等用户信息是常态,都或多或少会发送第三方 Cookie,更别提那些广告投放相关。

主要影响涉及以下:

  • 跨站点联合登录相关,Cookie 丢失无法正常登录
  • 联盟等广告站点 iFrame 投放,无法获取目标站点用户相关信息,无法精准推荐等
  • 接口需要跨站点请求,需要依赖 Cookie 的判断失效造成接口异常
  • 等等

只要涉及到 Cookie 跨站点传输的情况都多少会受到影响。

解决影响

当然像我碰到这个公司让用户去 chrome://flag 这样设置是行不通,甚至有点奇葩的行为。

比较稳妥的方法还是:在有针对性的做好 CSRF 防范的前提下,对 Cookie 内字段进行梳理,将必须要进行跨站请求携带 Cookie 的植入时添加 SameSite: none。

  • Expires: 过期时间,不设置为会话 Cookie 浏览器关闭后失效
  • Max-Age: 最大有效时间,秒数,Max-Age 优先级比 Expires 高
  • Domain: Cookie 生效的主机名,不设置为当前地址 host 部分,不含子域名,如: .baidu.com,x.baidu.com 也可以访问;注意不能跨域设置
  • Path: Cookie 生效的 URL 路径,这个路径必须出现在要请求的资源的路径中才可以发送 Cookie 首部。下级目录也可以满足:path=/docs,那么 “/docs”, “/docs/Web/“也满足
  • Secure: 安全标记,设置为 Secure 的 Cookie 只有在请求使用 SSL 和 HTTPS 协议的时候才会被发送到服务器。用 HTTPS 安全协议,保护 Cookie 在浏览器和服务器间传输中不被窃取和篡改
  • HttpOnly: 设置了 HttpOnly 属性的 cookie 不能使用 JavaScript 经由 Document.cookie 属性、XMLHttpRequest 和 Request APIs 进行访问,以防范跨站脚本攻击(XSS)

参考

MDN Set-Cookie

MDN SameSite cookies

维基百科 CSRF)

Cookie 的 SameSite 属性 - ruanyifeng

Cookie 的 SameSite 属性相关 - 冴羽

Chrome 80 後針對第三方 Cookie 的規則調整 (default SameSite=Lax))