CSRF

CSRF 跨站请求详解

CSRF(Cross-Site Request Forgery,跨站点伪造请求)是一种网络攻击方式,该攻击可以在受害者毫不知情的情况下以受害者名义伪造请求发送给受攻击站点,从而在未授权的情况下执行在权限保护之下的操作,具有很大的危害性。具体来讲,可以这样理解 CSRF 攻击:攻击者盗用了你的身份,以你的名义发送恶意请求,对服务器来说这个请求是完全合法的,但是却完成了攻击者所期望的一个操作,比如以你的名义发送邮件、发消息,盗取你的账号,添加系统管理员,甚至于购买商品、虚拟货币转账等。

  • token 机制。在 HTTP 请求中进行 token 验证,如果请求中没有 token 或者 token 内容不正确,则认为 CSRF 攻击而拒绝该请求。

  • 验证码。通常情况下,验证码能够很好的遏制 CSRF 攻击,但是很多情况下,出于用户体验考虑,验证码只能作为一种辅助手段,而不是最主要的解决方案。

  • referer 识别。在 HTTP Header 中有一个字段 Referer,它记录了 HTTP 请求的来源地址。如果 Referer 是其他网站,就有可能是 CSRF 攻击,则拒绝该请求。但是,服务器并非都能取到 Referer。很多用户出于隐私保护的考虑,限制了 Referer 的发送。在某些情况下,浏览器也不会发送 Referer,例如 HTTPS 跳转到 HTTP。

CSRF (Cross-site request forgery),中文名称:跨站请求伪造,也被称为:one click attack/session riding,缩写为:CSRF/XSRF。CSRF 与 XSS 在攻击手段上有点类似,都是在客户端执行恶意代码,有些文章中认为 CSRF 与 XSS 的区别在于 CSRF 不注重于获取用户 Cookie,笔者认为可能还有区别在于 CSRF 不仅可以在源站发起攻击,还可以引导用户访问其他危险网站的同时发起攻击。XSS 全程是跨站脚本攻击,即攻击者向某个 Web 页面中插入恶意的 JavaScript 脚本,而当普通用户访问时,该恶意脚本自动执行而从盗取用户的 Cookie 等信息。对于 XSS 的防御手段主要就是输入检查与输出检查,譬如对用户输入的文本框内容进行 <、> 这样的特殊字符检查。而输出检查则是指对于输出到网页的内容进行过滤或者编解码,譬如使用 HTML 编码将 < 转义。CSRF 为跨站请求伪造,其与 XSS 有点类似,不过区别在于 CSRF 不一定依赖于 JavaScript,并且不仅可以在源站发起攻击,还有可能当用户访问恶意网站时引导其访问原网站。CSRF 攻击是源于 WEB 的隐式身份验证机制,WEB 的身份验证机制虽然可以保证一个请求是来自于某个用户的浏览器,但却无法保证该请求是用户批准发送的。对于 CSRF 的防御也分为服务端防御与客户端防御两种,服务端防御典型的譬如给某个页面添加随机数,使得无法从第三方页面直接提交。在客户端防御的话可以利用譬如 Firefox 提供的一些检查工具。注意,CSRF 并没有打破同源策略。

以下面的这个例子来说:银行网站 A,它以 GET 请求来完成银行转账的操作,如:http://www.mybank.com/Transfer.php?toBankId=11&money=1000危险网站 B,它里面有一段 HTML 的代码如下:

<img src=http://www.mybank.com/Transfer.php?toBankId=11&money=1000>

银行网站 A 违反了 HTTP 规范,使用 GET 请求更新资源。在访问危险网站 B 的之前,你已经登录了银行网站 A,而 B 中的<img>以 GET 的方 式请求第三方资源(这里的第三方就是指银行网站了,原本这是一个合法的请求,但这里被不法分子利用了),所以你的浏览器会带上你的银行网站 A 的 Cookie 发出 Get 请求,去获取资源 “http://www.mybank.com/Transfer.php?toBankId=11& money=1000”,结果银行网站服务器收到请求后,认为这是一个更新资源操作(转账操作),所以就立刻进行转账操作。参考深入解析跨站请求伪造漏洞:原理剖析 (中所述,XSS 与 CSRF 的区别在于:

  • XSS 攻击需要 JavaScript,而 CSRF 攻击不需要。
  • XSS 攻击要求站点接受恶意代码,而对于 CSRF 攻击来说,恶意代码位于第三方站点上。过滤用户的输入可以防止恶意代码注入到某个站点,但是它无阻止法恶意代码在第三方站点上运行。

原因浅析

CSRF 攻击是源于 WEB 的隐式身份验证机制,WEB 的身份验证机制虽然可以保证一个请求是来自于某个用户的浏览器,但却无法保证该请求是用户批准发送的。假设 Alice 访问了一个恶意站点 M,该站点提供的内容中的 JavaScript 代码或者图像标签会导致 Alice 的浏览器向站点 T 发送一个 HTTP 请求。由于该请求是发给站点 T 的,所以 Alice 的浏览器自动地给该请求附上与站点 T 对应的该会话 cookie 的 sid。站点 T 看到该请求时,它就能通过该 cookie 的推断出:该请求来自 Alice,所以站点 T 就会对 Alice 的帐户执行所请求的操作。这样,CSRF 攻击就能得逞了。其他大多数 Web 认证机制也面临同样的问题。例如,HTTP BasicAuth 机制会要求 Alice 告诉浏览器她在站点 T 上的用户名和口令,于是浏览器将用户名和口令附加到之后发给站点 T 的请求中。当然,站点 T 也 可能使用客户端 SSL 证书,但这也面临同样的问题,因为浏览器也会将证书附加到发给站点 T 的请求中。类似的,如果站点 T 通过 IP 地址来验证 Alice 的身 份的话,照样面临 CSRF 攻击的威胁。总之,只要身份认证是隐式进行的,就会存在 CSRF 攻击的危险,因为浏览器发出请求这一动作未必是受用户的指使。原则上,这种威胁可以通过对每个发送至该 站点的请求都要求用户进行显式的、不可欺骗的动作(诸如重新输入用户名和口令)来消除,但实际上这会导致严重的易用性问题。大部分标准和广泛应用的认证机 制都无法防止 CSRF 攻击,所以我们只好另外探求一个实用的解决方案。