Php 简明教程

PHP – CSRF

缩写词“CSRF”代表跨站点请求伪造。CSRF 是一种 Internet 漏洞,涉及受信任网站用户的发出未经授权的命令。通过采取本章中说明的措施,可以为 PHP Web 应用程序提供充足的保护来防御此类攻击。

默认情况下,浏览器使用“GET”请求方法来发送数据。这通常用作 CSRF 中的利用点。为了将命令注入到特定网站中,攻击者会使用诸如“IMG”之类的 HTML 标签。例如,Web 应用程序的 URL 端点,如“/delete.php?empcode=1234”,会删除从 GET 请求的 empcode 参数中传递的帐户。现在,如果经过身份验证的用户在任何其他应用程序中遇到以下脚本。

<img src="http://example.com/delete.php?empcode=1234"
   width="0" height="0" border="0">

会不经意地导致与 empcode=1234 相关的数据被删除。

此问题的常见解决方法是使用 CSRF 令牌。CSRF 令牌是一串随机字符,嵌入到请求中,以便 Web 应用程序可以相信已从预期来源接收请求(按照正常工作流程)。

Steps to Implement CSRF

在 PHP 中实现 CSRF 令牌保护的步骤如下 -

  1. 通过启动新会话来开始脚本。

  2. 生成随机字符令牌。你可以使用 PHP 提供的几个内置函数来生成随机字符串。使用 md5() 函数来获取会生成唯一随机字符串的 uniqueid() 函数的哈希值。

  3. 在为用户准备以提交数据而提供的 HTML 表单内,包括一个隐藏文件,其值是上述步骤中生成的随机令牌。

  4. 在表单提交之后,服务器可以根据用户会话验证令牌,以消除恶意请求。

  5. 你还可以添加另一个赋值为当前时间的会话变量,并发送一个用于验证目的的到期时间。

Example

以下 PHP 代码实现了 CSRF 令牌验证机制。以下脚本生成一个令牌并将其嵌入到 HTML 表单中。

<?php
   session_start();
   if(!isset($_SESSION["csrf_token"])) {

      // No token present, generate a new one
      $token = md5(uniqid(rand(), true));
      $_SESSION["csrf_token"] = $token;

   } else {

      // Reuse the token
      $token = $_SESSION["csrf_token"];
   }
?>
<html>
<body>
   <form method="get" action="test.php">
      <input type="text" name="empcode" placeholder="empcode" />
      <input type="hidden" name="csrf_token" value="<?php echo $token;?>" />
      <input type="submit" />
   </form>
</body>
</html>

该表单提交到 "test.php" 脚本,如下所示 -

<?php
   session_start();
   echo "hello";
   if ($_GET["csrf_token"] == $_SESSION["csrf_token"]) {

      // Reset token
      echo $_GET["csrf_token"] . "<br>";
      echo $_SESSION["csrf_token"] . "<br>";
      echo "<h3>CSRF token validation successful. Proceed to further action</h3>";
   } else {
      echo "<h3>CSRF token validation failed</h3>";
   }
?>

它将生成以下 output

php csrf

要模拟 CSRF 验证失败,请打开浏览器的检查工具,手动编辑隐藏字段中的值,然后提交表单以查看令牌不匹配,从而导致验证失败。