原文地址:
Cross-Site Request Forgery is dead!
https://scotthelme.co.uk/csrf-is-dead/
对于WEB CSRF(跨站请求伪造)攻击,解决方案一直以来都比较复杂。传统的csrf token解决方法,要求网站管理者拥有专业的技术知识,现在我们找到了一个更好的解决方案————Same-Site Cookies,这种方案让网站管理者告别技术负担,并且不再需要复杂的操作,就能非常简单地完成csrf防护。
CSRF历史
众所周知,跨站请求伪造(也称为CSRF或XSRF)一直就存在,这就好比一个网站向另一个网站发起请求,假设我在一个页面中嵌入了以下表单:
当浏览器加载此页面时,会渲染上面的表单,然后我们使用一个简单的JS:
document.getElementById("stealMoney").submit();
我在另一个网站,伪造了一个请求发送给银行网站。这里的真正问题不在于我发送请求,而是浏览器会将cookies带上一并发出去。这个伪造的请求将拥有当前用户的完整权限,这意味着如果用户登录了银行网站,用户将会向我捐赠1,000英镑。 谢谢! 如果用户没有登录,那么请求将是无害的,因为伪造的请求无法在没有登录的情况下转移资金。
针对这个情况,银行网站有几种方法可以减轻这些CSRF攻击。
CSRF防护措施
本文不会详细讲解防护csrf的原理,大家可以通过网络搜到很多这些方面的文章。为了更好的理解后面的内容,我会尽量快速简单的给大家过一遍。
1. 检查来源
当服务器收到请求时,可能会收到两个有用的字段信息,这两个信息可以告诉服务器请求来自哪里。 这两个字段分别是Origin和Referer。我们可以检查它们中的一个或两个,来确认请求是否来自同一个网站。 如果请求是跨站的,出于安全我们不处理。
Origin和Referer确实可以起到安全作用,防止请求伪造,但是这两个字段可能并不总是存在。
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
2. 防CSRF令牌机制
有两种不同的方法可以实现防CSRF令牌机制,但是原理是一样的。
当访客请求一个页面时,比如上面的示例中的转账页面,我们可以在表单中嵌入一个随机token(一般叫csrf token)。当真实用户提交此表单时,随机token也会跟着提交,服务器可以检查提交请求中的token是否和表单中的令牌匹配。在CSRF攻击场景中,攻击者永远不会获得token值,即使他们请求了转账页面,因为同源策略(SOP)将阻止攻击者读取包含该令牌的响应。这种方法比较行之有效,但要求服务器管理csrf token的生成和校验。
第二种类似的方法,是将token嵌入到表单中,并向浏览器写入相同值的cookie。当真实用户提交请求时,会将表单数据和cookie数据都提交上去,服务器进行匹配。当攻击者发送伪造的请求时,浏览器将不会设置CSRF cookie,攻击将失败。
<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%可靠,大多数站点会根据情况进行适应,我们需要对网站增加专门的csrf防护方案。虽然csrf防护,可能不是非常复杂的技术,但是我们也看到了,为了csrf攻击得到解决,我们围绕浏览器做了很多额外的操作,这些操作都与业务没有关系。
难道我们一定要做这些额外的事情么?现在我们有了新的答案!
Same-Site Cookies
想要深入了解cookie,可以参考我的这篇文章:
https://scotthelme.co.uk/tough-cookies/
我会提供几个例子以便大家深入理解Same-Site Cookies,基本上,它可以完全有效地阻止CSRF攻击。
哈,CSRF————死了!结束了!一路平安!
对于哪些希望得到安全保护的cookie,使用非常简单,这是目前的常见一个cookie:
加上Same-Site之后的样子:
完成了。怎么样,很简单吧!
cookie上启用Same-Site属性时,浏览器将会自动对该cookie进行保护。保护一共有两种模式,分别是Strict和Lax,具体取决于我们网站的安全程度。默认情况下,取Strict,但如果需要,也可以明确设置Strict或者Lax。
SameSite=Strict
SameSite=Lax
1. Strict(严格模式)
将SameSite属性设置为严格模式显然是首选,但这种模式并不适合所有网站。
在严格模式下运行时,浏览器将不会发送任何跨站请求的cookie,所以可以使CSRF彻底失败。但是我们会遇到的最大问题是,点击其它网站跳转时,它也不会发送cookie。
如果我的网站有一个指向https://facebook.com的链接,并且Facebook将SameSite Cookie设置为严格模式,当用户点击链接打开Facebook时,用户将不会登录。无论用户是否已经登录,无论用户做了什么,用户都不会在从该链接访问时登录到Facebook。这可能会让用户不爽或者感到意外,但确实提供了令人难以置信的强大的保护。
刚才的例子确实有问题,需要修改Facebook策略,可以参考亚马逊的做法。亚马逊提供2个cookie,一种是基本的cookie,用于进行用户标识,并允许用户具有登录体验,但如果用户想做一些敏感的事情,比如进行购买或更改帐户时,就需要更严格的cookie。
基本的cookie做普通的事情,严格的cookie做重要的事情。
在这种情况下,基本的cookie不会将SameSite属性设置为Lax,方便用户使用。严格的cookie设置SameSite属性为Strict,攻击者不能滥用进行csrf攻击。这是用户体验和安全性的理想解决方案。
2. Lax(松散模式)
将SameSite设置为松散模式,可以解决在用户点击链接的严格模式下的问题,如果用户已经登录,则不会在目标站点上登出。
在Lax模式下,RFC 7321的4.2.1节中定义GET,HEAD,OPTIONS和TRACE这些方法会保留cookie,我们对GET方法感兴趣。这意味着当用户点击链接时,浏览器发出请求时,会带上标记为Lax的cookie,保证了预期的用户体验。
Lax,会对POST的CSRF攻击进行保护保护,就像最开始提到的那个例子,使用Lax可以避免csrf攻击。
因为在松散模式下,POST方法依旧不被认为是安全的,所以浏览器不会在请求中附加cookie。
在web开发时,我们一定要注意,不要允许get请求代替post请求,因为这样会导致lax模式下的csrf攻击。此外,如果攻击者可以触发弹出新窗口,还可能导致浏览器发出带有附加cookie的GET请求。所以在Lax模式下,我们保持用户体验完整,但是可能会有一些风险。
附加用途
本篇文章的目的是使用SameSite Cookies进行CSRF防护,大家可能已经猜到了,这种机制还有其他用途。
第一个是跨站脚本包含攻击方法(XSSI),它是浏览器对脚本的请求,该脚本将根据用户是否被认证而改变。在跨站请求场景中,攻击者不能滥用SameSite Cookie以产生不同的响应。
另一个有趣的用法是防止在BEAST攻击(CLIME,BREACH,HEIST,TIME),这里不详细介绍。这类攻击,会泄露会话cookie的值。中间人攻击一般会通过跨站发起攻击请求,并通过有效载荷大小的变化,来猜测会话ID值。使用SameSite Cookie浏览器不会在此类请求中包含Cookie,因此攻击者无法猜测其值。
浏览器支持
随着浏览器安全功能的更新,期待Firefox或Chrome等浏览器陆续采用,目前Chrome 51版本之后已经全部支持SameSite属性。这意味着Opera,Android浏览器和Android平台的Chrome等,都已经支持。
我们可以在caniuse.com上看到列出当前支持的详细信息:
http://caniuse.com/#search=SameSite
Firefox bug关于SameSite支持的记载:
https://bugzilla.mozilla.org/show_bug.cgi?id=795346
目前SameSite Cookie还不是很普及,但还是建议网站支持这个属性。这样会让支持它的浏览器访问更安全,不支持的浏览器也不会造成任何影响。
forgery | 伪造 |
toiling | 辛苦,劳累 |
implementation | 履行,完成 |
burden | 负担 |
trivially | 平凡的 |
mitigation | 缓解,平缓,防护措施 |
origin | 起源,来源 |
potentially | 潜在的 |
tampering | 鼓捣,篡改 |
anti- | (前缀)反对,防止 |
embed | 把……潜入 |
genuine | 真的 |
scenario | 剧本,剧情 |
robust | 强壮的,强健的 |
complicate | 使复杂化 |
neutralise | 抵消,废弃 |
dead/finito/adios | 死掉/终止/再见 |
lax | 松的,不严格的 |
Leave a Reply