Section outline

  • 为了防御 CSRF 攻击,Web 应用程序可以将秘密令牌嵌入到页面中。所有来自这些页面的请求都必须携带此令牌,否则会被视为跨站请求,不会具有和同源请求相同的权限。攻击者无法获取此秘密令牌,因此他们的请求很容易被识别为跨站请求。

    Elgg} 使用这种秘密令牌方法作为其内置的防护措施来防御 CSRF 攻击。我们已经关闭了这些防护措施以使攻击生效。 Elgg 在请求中嵌入了两个参数 __elgg_ts 和 __elgg_token。服务器在处理请求前会验证它们。

    将秘密令牌和时间戳嵌入到网页中:Elgg 在所有需要用户操作的地方都添加了安全令牌和时间戳。以下 HTML 代码出现在所有的表里。这两个隐藏字段会在表单提交时被附加到请求中:
    <input type = "hidden" name = "__elgg_ts" value = "" />
    <input type = "hidden" name = "__elgg_token" value = "" />

    Elgg 还将安全令牌和时间戳的值赋给 JavaScript 变量,以便页面上的 JavaScript 代码可以轻松访问这些变量。
    elgg.security.token.__elgg_ts;
    elgg.security.token.__elgg_token;

    在 Elgg} 的网页中添加安全令牌和时间戳是通过 vendor/elgg/elgg/views/default/input/securitytoken.php 来实现的。下面的代码片段展示了这些内容是如何动态地添加到页面上的。
    $ts = time();
    $token = elgg()->csrf->generateActionToken($ts);
    
    echo elgg_view('input/hidden', ['name' => '__elgg_token', 'value' => $token]);
    echo elgg_view('input/hidden', ['name' => '__elgg_ts', 'value' => $ts]);

    秘密令牌的生成。Elgg 的安全令牌是下面信息产生的哈希值:网站提供的秘密值,时间戳、用户会话 ID 和随机生成的会话字符串。下面的代码展示了 Elgg 中的安全令牌的生成过程(在 vendor/elgg/elgg/engine/classes/Elgg/Security/Csrf.php 中)。
    /**
     * 从会话令牌、时间戳和站点密钥生成一个令牌。
     */
    public function generateActionToken($timestamp, $session_token = '') {
      if (!$session_token) {
              $session_token = $this->session->get('__elgg_session');
              if (!$session_token) {
                      return false;
              }
      }
    
      return $this->hmac
              ->getHmac([(int) $timestamp, $session_token], 'md5')
              ->getToken();
    }

    秘密令牌验证。 Elgg} 网站会验证生成的令牌和时间戳以防御 CSRF 攻击。每当用户执行某个操作时,都会调用 Csrf.php 中的 validate() 函数,此函数会对这些令牌进行验证。如果令牌不存在或无效,则将拒绝该操作并将用户重定向到其他页面。我们在该函数开始添加了一个 return 语句,从而禁用了这一功能。
    public function validate(Request $request) {
       (*@\textbf{return;}@*) // 为 SEED 实验(禁用 CSRF 防护措施)而添加
    
        $token = $request->getParam('__elgg_token');
        $ts = $request->getParam('__elgg_ts');
        ... (省略了代码)
    }

     
    任务:开启防护措施。为了启用防护措施,请进入 Elgg 容器,前往 /var/www/elgg/vendor/elgg/elgg/engine/classes/Elgg/Security 文件夹,从  Csrf.php 中删除 return 语句。容器内有一个简单的编辑器叫做 nano。在完成更改后,请重新运行攻击,并观察您的攻击是否成功。请指出捕获的 HTTP 请求中的秘密令牌。请解释为什么攻击者无法在 CSRF 攻击中发送这些秘密令牌;是什么阻止了他们从网页中找到这些秘密令牌?

    需要注意的是(非常重要),当我们启用防护措施后进行CSRF攻击去修改个人资料时,攻击失败后攻击者的页面会被重新载入,这将再次触发伪造的 POST 请求。这会导致另一个失败的攻击,然后页面将继续被重新加载并发送出另一个伪造的 POST 请求。这种无限循环可能会导致您的计算机变慢。因此,在确认攻击失败后,请关闭页面以停止无限循环。