防御修复

CSRF 漏洞防御与修复

服务端防御

遵循标准的 GET 动作

只允许 GET 请求检索数据,但是不允许它修改服务器上的任何数据。这个修改可以防止利用 {img} 标签或者其它的类型的 GET 请求的 CSRF 攻击。另外,这个建议遵循 RFC 2616(HTTP/1.1):具体说来,按照约定,GET 和 HEAD 方法不应该进行检索之外的动作。这些方法应该被认为是 “ 安全的 ”。虽然这个保护措施无法阻止 CSRF 本身,因 为攻击者可以使用 POST 请求,但是它却可以与 (2) 结合来全面防止 CSRF 漏洞。这里,我们假定对手无法修改用户的 cookie。

为页面增加随机数

当用户访问站点时,该站点应该生成一个(密码上很强壮的)伪随机值,并在用户的计算机上将其设为 cookie。站点应该要求每个表单都包含该伪随机 值(作为表单值和 cookie 值)。当一个 POST 请求被发给站点时,只有表单值和 cookie 值相同时,该请求才会被认为是有效的。当攻击者以一个用户的名义提交表单时,他只能修改该表单的值。攻击者不能读取任何发自该服务器的数据或者修改 cookie 值,这是同源策略的缘故。这意味着,虽然攻击者可以用表单发送任何他想要的值,但是他却不能修改或者读取存储在该 cookie 中的值。因为 cookie 值和表单值必须是相同的,所 以除非攻击者能猜出该伪随机值,否则他就无法成功地提交表单。以 PHP 为例,我们可以在服务端首先生成随机数:

 <?php
    // 构造加密的Cookie信息
    $value = “DefenseSCRF”;
    setcookie(”cookie”, $value, time()+3600);
  ?>

在表单里增加 Hash 值,以认证这确实是用户发送的请求。

<?php
    $hash = md5($_COOKIE['cookie']);
  ?>
  <form method=”POST” action=”transfer.php”>
    <input type=”text” name=”toBankId”>
    <input type=”text” name=”money”>
    <input type=”hidden” name=”hash” value=”<?=$hash;?>”>
    <input type=”submit” name=”submit” value=”Submit”>
  </form>

然后在服务器端进行 Hash 值验证:

      <?php
        if(isset($_POST['check'])) {
             $hash = md5($_COOKIE['cookie']);
             if($_POST['check'] == $hash) {
                  doJob();
             } else {
        //...
             }
        } else {
      //...
        }
      ?>

当然,我们也可以强制要求用户进行任何增删改的操作时都需要输入验证码,即进行用户交互,不过这样也就意味着很差的用户体验。

客户端防御

由于使攻击者成功地执行 CSRF 攻击的请求是由浏览器发出的,所以可以创建客户端工具来保护用户不受此种攻击。现有的工具 RequestRodeo 通过在客户和服务器之间充当代理来防止 CSRF 攻击。如果 RequestRodeo 发现了一个它认为是非法的请求,它会从该请求剥离验证信息。虽然这种方 式在很多情况下都能有效,但是它具有一些局限性。具体地说,当客户端使用了 SSL 认证或者使用 JavaScript 生成部分页面(因为 RequestRodeo 分析的是在浏览器显示之前的流经代理的那些数据)时,它就不起作用了。人们已经开发了一个浏览器插件,不仅可以使用户可以免受某些类型的 CSRF 攻击,并且还能克服以上所述的局限性,这个工具是作为 Firefox 浏览器的扩展实现的,其地址是http://www.cs.princeton.edu/˜wzeller/csrf/protector/。为了有效地防范 CSRF 攻击,用户需要下载安装这个扩展。该扩展会拦截所有的 HTTP 请求,并判断是否允许该 HTTP 请求。这个判断要用到下列规则。首 先,POST 请求之外的任何要求都是允许的。第二,如果发出请求的站点和目标站点符合同源策略的要求,那么该请求被允许。第三,如果发出请求的站点被允许 使用 Adobe 的跨域政策来建立一个请求的话,那么该请求也会被允许。如果我们的扩展拒绝一个请求,该扩展会通过一个常见的界面来提示用户(即 Firefox 所使用的 popup blocker)该请求已经被阻止,并且让用户选择是否将站点添加到一个白名单中。该扩展仅仅拦截 POST 请求。这意味着,它无法保护用户免受使用 GET 请求的 CSRF 攻击 阻止这种类型的攻击的唯一方法是不允许任何跨域 GET 请求,或只允许用户一次只能登录到一个站点,但是这两个限制可能是用户无法忍受的。

下一页