浅析跨站请求伪造(CSRF)攻击

概述

介绍下列内容:

  • 什么是 CSRF 攻击
  • 漏洞举例
  • 常见的防御方式

什么是CSRF攻击

狭义的CSRF攻击

狭义的CSRF攻击就是指让Client在被Server认证的情况下去访问精心设计的恶意链接完成攻击。

  1. 因为 HTTP 是无状态的协议,即 Server 不知道每个请求来源于哪个用户。
  2. 所以服务器有时会在Client存储可以标识用户身份的信息。
  3. 在Client发送请求的时候附上用户身份信息保证Server可以识别出用户。
  4. 如果此时用户点击了一个恶意链接,且恶意链接会发送一个恶意请求到 Server。
  5. 一般情况下会因为不能识别用户身份而而被拒绝。
  6. 但是如果此时 Client 是刚刚被服务端认证过的,则发送恶意请求的同时也会附上刚刚认证的身份信息。
  7. Server 收到恶意请求后发现Client是认证过的,于是将其识别为合法请求。
  8. 攻击者就完成了一次 CSRF 攻击。

广义的CSRF攻击

通过一些手段猜测出请求参数以及用户认证信息(如果需要认证的话),这样Server就会将其识别为合理请求。


例如某网站转账的URL为https://www.bank.com/transfer?user=小明&money=1000&for=小红,代表小明转账给小红 1000 元。那么攻击者就可以构造出这个URL—https://www.bank.com/transfer?user=小明&money=9999999999&for=小李直接掏空小明的钱。

漏洞举例

常见的防御方式

验证码

在执行一些重要请求之前通过验证码的方式验证用户身份,例如短信验证码,图片验证码等。所以你会发现许多网站即使在登录状态先执行一些操作也需要验证。

同源检测

根据 HTTP 协议,在 HTTP 头中有一个字段叫 Referer,记录了该HTTP请求的来源地址。 对于 Ajax 请求,图片和 script 等资源请求,Referer 为发起请求的页面地址。对于页面跳转,Referer 为打开页面历史记录的前一个页面地址。因此我们使用 Referer 中链接的 Origin 部分可以得知请求的来源域名。


这种方法并非万无一失,Referer 的值是由浏览器提供的,虽然 HTTP 协议上有明确的要求,但是每个浏览器对于 Referer 的具体实现可能有差别,并不能保证浏览器自身没有安全漏洞。使用验证 Referer 值的方法,就是把安全性都依赖于第三方(即浏览器)来保障,从理论上来讲,这样并不是很安全。在部分情况下,攻击者可以隐藏,甚至修改自己请求的 Referer。

同源验证是一个相对简单的防范方法,能够防范绝大多数的 CSRF 攻击。但这并不是万无一失的,对于安全性要求较高,或者有较多用户输入内容的网站,我们就要对关键的接口做额外的防护措施。

CSRF Token

CSRF 攻击之所以能够成功,是因为服务器误把攻击者发送的请求当成了用户自己的请求。那么我们可以要求所有的用户请求都携带一个CSRF攻击者无法获取到的 Token。服务器通过校验请求是否携带正确的 Token,来把正常的请求和攻击的请求区分开,也可以防范 CSRF 的攻击。


通过一套合适的规则(一般来说这套规则要便于分布式校验)来生成随机的 Token 并跟随 form 表单一起提交,由于 HTTPS 在传输过程中是加密的,所以攻击者无法截获 Token,前提是站点没有 XSS 漏洞。

但是此方法的实现比较复杂,需要给每一个页面都写入 Token(前端无法使用纯静态页面),每一个 Form 及 Ajax 请求都携带这个 Token,后端对每一个接口都进行校验,并保证页面 Token 及请求 Token 一致。这就使得这个防护策略不能在通用的拦截上统一拦截处理,而需要每一个页面和接口都添加对应的输出和校验。这种方法工作量巨大,且有可能遗漏。

双重Cookie验证

在会话中存储CSRF Token比较繁琐,而且不能在通用的拦截上统一处理所有的接口。
那么另一种防御措施是使用双重提交Cookie。利用CSRF攻击不能获取到用户Cookie的特点,我们可以要求Ajax和表单请求携带一个Cookie中的值。


双重Cookie采用以下流程:

  • 在用户访问网站页面时,向请求域名注入一个Cookie,内容为随机字符串(例如csrfcookie=v8g9e4ksfhw)。
  •  在前端向后端发起请求时,取出Cookie,并添加到URL的参数中(接上例POST https://www.a.com/comment?csrfcookie=v8g9e4ksfhw)。
  • 后端接口验证 Cookie 中的字段与 URL 参数中的字段是否一致,不一致则拒绝。

攻击者可以获取到URL参数中的Token值,但是无法获取到Cookie中的Token值,因此攻击者无法构造出恶意链接。


你可能会想既然我已经截取到了URL参数中的Token值,那么攻击者也就可以猜测出Cookie中的Token值。对,没错,因为上面的流程中URL参数和Cookie中存储的是相同的值,那么如果我对Cookie中的值进行加密呢?那么攻击者就无法推测出Cookie的内容了。

此方法相对于CSRF Token就简单了许多。可以直接通过前后端拦截的的方法自动化实现。后端校验也更加方便,只需进行请求中字段的对比,而不需要再进行查询和存储Token。


当然,此方法并没有大规模应用,其在大型网站上的安全性还是没有CSRF Token高,因为任何跨域都会导致前端无法获取Cookie中的字段(包括子域名之间)。

参考资料

本文作者:ADD-SP
本文链接https://www.addesp.com/archives/218
版权声明:本博客所有文章除特别声明外,均默认采用 CC-BY-NC-SA 4.0 许可协议。
暂无评论

发送评论 编辑评论


上一篇
下一篇