CSRF 攻击已死!

文章介绍了 CSRF 攻击的由来,攻击方式以及一些防御手段,之后说明了在用户和安全上的一个权衡,了解了 CSRF 攻击在浏览器的更新迭代,以及站点安全的提高下慢慢失去作用。

原文:

Cross-Site Request Forgery is dead!

术语表:

原文译文说明
Cross-Site Request Forgery跨站点请求伪造一种 web 攻击方式
cookiecookie浏览器存储数据的一种方式,专业术语,保留原文不译
the Same Origin Policy同源策略浏览器的其中一种策略
Same-Site Cookies同站点 cookie

翻译

在网上费尽心思伪造网站请求之后,我们终于找到了一个合适的解决方案。对站点所有者来说没有技术负担,没有困难的实现,部署起来非常简单,就是同一个站点 cookie。

与 Web 本身一样老

跨站点请求伪造,也称为 CSRF 或 XSRF,基本上一直存在。它源于网站必须向另一个站点发出请求这样一个的简单功能。假设我在此页面中嵌入了以下表单。

<form action="https://your-bank.com/transfer" method="POST" id="stealMoney">
<input type="hidden" name="to" value="Scott Helme">
<input type="hidden" name="account" value="14278935">
<input type="hidden" name="amount" value="£1,000">

你的浏览器加载了这个页面,结果是上面的表单,之后我再在我的页面上使用一个简单的 JS 提交。

document.getElementById("stealMoney").submit();

这就是 CSR F的这个名字的由来。我伪造了一个请求,正在跨网站发送信息到你的银行。而这里真正的问题不是我发送了请求,而是你的浏览器会发送你的 cookie。该请求会在此时以你当前持有的全部权限发送信息,这意味着如果你已经登录到你的网上银行的话,你需向我捐赠 1,000 英镑。感谢!如果你没有登录,那么请求将是无害的,因为你无法在未登录的情况下转账。目前,你的网银有这么几种方法可以减轻这些 CSRF 攻击。

CSRF缓解措施

我不会详细说明这些,因为网上有大量有关这个主题的信息,但我想快速介绍它们来展示实施它们的一些技术要求。

检查原点

收到请求时,我们可能收到两条向我们说明请求来源的信息。这就是 Origin 头和 Referer 头。你可以检查这些值中的一个或两个,来查看请求是否来源于你自己的其他不同来源。如果请求是跨域请求,就只需将其丢弃即可。Origin 和 Referer 头确实得到了一些浏览器的保护,以防止被篡改,但它们可能并不总是存在。

accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
accept-encoding: gzip, deflate, br
cache-control: max-age=0
content-length: 166
content-type: application/x-www-form-urlencoded
dnt: 1
origin: https://report-uri.io
referer: https://report-uri.io/login
upgrade-insecure-requests: 1
user-agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36

反 CSRF 令牌

你可以使用两种不同的方式来使用 Anti-CSRF 令牌,但原理不变。当访问者请求页面时,如上例中的转移金额的页面,你就可以将随机令牌嵌入到表单中。当真正的用户提交这个表单的时候,就会返回随机令牌,你可以检查它是否与你在表单中发送的令牌相匹配。在 CSRF 攻击这个情形中,攻击者是永远无法获得这个值的,即使他们请求对应的页面也办法,因为同源策略(SOP)会阻止攻击者读取包含令牌的响应。这种方法运行良好,但要求站点跟踪 Anti-CSRF 令牌的发布和返回。另外类似的方法是将令牌嵌入到表单中,并向浏览器发出包含相同的 cookie 内容。当真正的用户提交他们的表单时,网站就会收到 cookie 中的值和表单内容,之后进行匹配。当攻击者发送伪造请求时,浏览器将不会设置 CSRF cookie,测试就会失败。

<form action="https://report-uri.io/login/auth" method="POST">
    <input type="hidden" name="csrf_token" value="d82c90fc4a14b01224gde6ddebc23bf0">
    <input type="email" id="email" name="email">
    <input type="password" id="password" name="password">
    <button type="submit" class="btn btn-primary">Login</button>
</form>

问题

上述方法在长时间中为我们提供了相当强大的 CSRF 保护。检查 Origin 和 Referer 头并不是100%可靠,并且大多数站点会采用 Anti-CSRF 令牌方法的一些变体。问题是,这些都对网站提出了某种要求来实施和维护这个解决方案。它们可能不是世界上最复杂的技术,但是我们仍然在构建一个解决方案,围绕着浏览器做一些我们不希望它做的事情。相反,为什么我们不告诉浏览器停止做我们不希望它做的事情?…现在我们可以!

同站点 Cookie

你可能已经在我最近的一篇名为 Tough Cookies 的博客中看到过 Same-Site Cookies,但我会在这里通过一些例子更深入地介绍它。从本质上讲,Same-Site Cookies 完全有效抵御了 CSRF 攻击。得到了我们在网络上真正需要的东西来赢得安全战,Same-Site Cookies 易于部署,非常简单。拿你现有的 cookie:

Set-Cookie: sess=abc123; path=/

只需添加 SameSite 属性即可。

Set-Cookie: sess=abc123; path=/; SameSite=lax

你完成了。说真的,就是这样!在 cookie 上启用这个属性将指示浏览器为这个 cookie 提供某些保护。开启保护提供有两种模式:Strict 或 Lax ,具体取决于你想要获得的保护程度。

SameSite=Strict
SameSite=Lax

Strict(严格)

将 SameSite 保护设置为严格模式显然是首选,但我们有两种保护程度的原因是并非所有站点都相同,所以也没有一样的要求。当在严格模式下操作时,浏览器根本不会在任何跨源请求上发送 cookie ,因此 CSRF 完全沉沦。你可能遇到的唯一问题就是它也不会在顶级导航上发送 cookie(更改地址栏中的URL)。如果我提供了https://facebook.com的链接,并且 Facebook 将 SameSite cookie 设置为严格模式,当你点击链接到打开 Facebook 的链接时,你就会无法登录。无论你是否已经登录,都可以在新选项卡中打开它,并且无论你做什么,从该链接访问时都不会登录到你的 Facebook 。这对用户来说可能有点烦人或意外,但这确实提供了令人难以置信的强大保护。Facebook 在这里需要做的是类似于亚马逊所做的,他们有 2 个 cookie 。其中一种是 “基本” 的 cookie ,可以将你识别为用户,并允许你拥有登录体验,但如果你想做一些敏感的事情,比如购买或更改帐户中的内容,则需要第二个 cookie , “真正” 的 cookie,可以让你做更重要的事情。在这种情况下,第一个 cookie 不会设置 SameSite 属性,因为它是一个 “方便” 的 cookie ,它实际上不允许你做任何敏感的事情,如果攻击者用它做出跨域请求,则没有任何反应。但是,第二个 cookie(敏感 cookie )将设置 SameSite 属性,并且攻击者不能滥用其在跨源请求中的权限。这是用户和安全性的结合的理想解决方案。但这并不总是可行的,因为我们希望 SameSite cookie 易于部署,这当然还有第二种选择。

Lax(不严格的)

将 SameSite 保护设置为 Lax 模式可以修复上述用户点击链接的严格模式中提到的问题,如果他们已经登录,则不会登录到目标站点重新登陆。在 Lax 模式下,有一个例外,允许将 cookie 附加到使用安全 HTTP 方法的顶级导航中。这 “安全” 的 HTTP 方法在 RFC 7321 的 4.2.1 节中定义为 GET,HEAD,OPTIONS 和 TRACE,我们对这里的GET 方法感兴趣。这意味着,当用户单击链接时,我们对https://facebook.com的顶级导航现在在浏览器发出请求时附加了 SameSite 标记的 cookie,从而保持了预期的用户体验。我们还完全受惠于基于 POST 的 CSRF 攻击的保护。回到一开始的示例,这种攻击仍然无法在 Lax 模式下工作。

<form action="https://your-bank.com/transfer" method="POST" id="stealMoney">
<input type="hidden" name="to" value="Scott Helme">
<input type="hidden" name="account" value="14278935">
<input type="hidden" name="amount" value="£1,000">

但由于 POST 方法不被认为是安全的,因此浏览器不会在请求中附加 cookie。攻击者当然可以自由地将方法更改为 “安全” 方法并发出相同的请求。

<form action="https://your-bank.com/transfer" method="GET" id="stealMoney">
<input type="hidden" name="to" value="Scott Helme">
<input type="hidden" name="account" value="14278935">
<input type="hidden" name="amount" value="£1,000">

只要我们不接受 GET 而接收 POST 请求,那么这种攻击是不可能的,但是在 Lax 模式下操作时需要注意。此外,如果攻击者可以触发顶级导航或弹出新窗口,他们还可以使浏览器发出附加了 cookie 的 GET 请求。这是在 Lax 模式下运营的权衡,我们保持用户体验不变,但接受付款的风险很小。

其他用途

此博客旨在使用 SameSite Cookie 来缓解 CSRF,但正如你可能已经猜到的那样,这个机制也有其他用途。规范中列出的第一个是跨站点脚本包含(XSSI),浏览器在此处请求资源,例如脚本,该脚本将根据用户是否经过身份验证而更改。在跨站点请求方案中,攻击者不能滥用 SameSite Cookie 的环境权限来产生不同的响应。这里详细介绍了一些有趣的计时攻击,也可以减轻。

另一个虽然不详细但有趣用途是防止在 BEAST 式压缩攻击(CRIMEBREACHHEISTTIME)中泄露会话 cookie 的价值。这是非常高级的攻击方式,其中的基本场景是 MiTM 可以强制浏览器通过他们喜欢的任何机制发出跨源请求并监视它们。通过滥用请求有效负载大小的更改,攻击者可以通过改变浏览器发出的请求并在线路上观察它们的大小,一次一个字节地猜测会话 ID 值。使用 SameSite Cookies,浏览器不会在此类请求中包含cookie ,因此攻击者无法猜测其中的值。

浏览器支持

随着浏览器中有了大多数新的安全特性,你可以期待 Firefox 或 Chrome 会领先,而这里的情况也没有什么例外。自 v51 以来,Chrome 已经支持 Same-Site Cookies ,这意味着 Android 上的 Opera,Android 浏览器和Chrome 也有支持。你可以在 caniuse.com 上查看列出当前支持的详细信息,Firefox 也有一个 bug,可以添加支持。尽管支持尚未普及,但我们仍应将 SameSite 属性添加到 cookie 中。理解它的浏览器将尊重这个设置并提供cookie 额外的保护,而那些不理解它的浏览器将会完全忽略它并继续运行。这里没有什么可失去的,它形成了一个非常好的防御深度方法。我们可以考虑删除传统的反 CSRF 机制,但是在这些机制之上添加 SameSite 会给我们带来难以置信的强大防御。

生词

be dead in the water:沉沦,一蹶不振…

lax:n. 松元音;泻肚;adj. 松懈的;松的;腹泻的

mitigate:vt. 使缓和,使减轻;vi. 减轻,缓和下来

分类: 生活

0 条评论

发表回复

您的电子邮箱地址不会被公开。