Web 开发安全 - 防御篇|青训营笔记

100 阅读2分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第13天

面临错综复杂的网络环境,在了解哪些手段会造成 Web 安全事故之后,本节课将通过第二种「防御者」角色的视角,剖析不同攻击手段的技术细节,帮助大家逐个击破安全漏洞,更好地维护 Web 安全。

《Web 安全漏洞之 CSRF》中我们了解到,CSRF 的本质实际上是利用了 Cookie 会自动在请求中携带的特性,诱使用户在第三方站点发起请求的行为。除了文中说的一些解决方式之外,标准还专门为 Cookie 增加了 SameSite 属性,用来规避该问题。Chrome 于 2015 年 6 月支持了该属性,Firefox 和 Safari 紧随其后也增加了支持。SameSite 属性有以下几个值:

  • SameSite=None:无论是否跨站都会发送 Cookie
  • SameSite=Lax:允许部分第三方请求携带 Cookie
  • SameSite=Strict:仅允许同站请求携带 Cookie,即当前网页 URL 与请求目标 URL 完全一致

该属性适合所有在网页下的请求,包括但不限于网页中的 JS 脚本、图片、iframe、接口等页面内的请求。可以看到 None 是最宽松的,和之前的行为无异。而 Lax 和 Strict 都针对跨站的情况下做了限制。其中 Strict 最为严格,不允许任何跨站情况下携带该 Cookie。Lax 则相对宽松一点,允许了一些显式跳转后的 GET 行为携带。以下是一个带有 SameSite 属性的标准 Cookie 响应示例:

Set-Cookie: name=lizheming; SameSite=None; Secure

需要注意的是,浏览器做了仅针对 HTTPS 域名才支持 SameSite=None 配置。所以如果你要设置 SameSite=None 的话,则必须还要携带 Secure 属性才行。 可以看到同域的判断比较严格,需要 protocolhostnameport 三部分完全一致。相对而言,Cookie 中的同站判断就比较宽松,主要是根据 Mozilla 维护的公共后缀表(Pulic Suffix List)使用有效顶级域名(eTLD)+1的规则查找得到的一级域名是否相同来判断是否是同站请求。

例如 .org 是在 PSL 中记录的有效顶级域名,imnerd.org 则是一级域名。所以 https://blog.imnerd.org 和 https://www.imnerd.org 是同站域名。而 .github.io 也是在 PSL 中记录的有效顶级域名,所以 https://lizheming.github.io 和 https://blog.github.io 得到的一级域名是不一样的,他们两个是跨域请求。

在类似 GitHub/GitLab Pages, Netlify, Vercel 这种提供子域名给用户建站的第三方服务中,eTLD 的这种同站判断特性往往非常有用。通过将原本是一级域的域名添加到 eTLD 列表中,从而让浏览器认为配有用户名的完整域名才是一级域,有效解决了不同用户站点的 Cookie 共享的问题。