PHP – CSRF 跨站请求伪造



缩写“CSRF”代表跨站请求伪造。CSRF是一种互联网漏洞,它涉及受信任的网站用户发出未经授权的命令。通过采取本章中解释的措施,可以为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应用程序可以信任已从预期的源(根据正常工作流程)接收请求。

实现CSRF的步骤

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

  • 启动脚本,开始一个新会话。

  • 生成一个随机字符令牌。可以使用PHP提供的几个内置函数中的任何一个来生成随机字符串。让我们使用md5()函数来获取生成唯一随机字符串的uniqueid()函数的哈希值。

  • 在提供给用户提交数据的HTML表单中,包含一个隐藏字段,其值为上述步骤中生成的随机令牌。

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

  • 您还可以添加另一个会话变量,其值为当前时间,并发送一个到期时间以进行验证。

示例

这是实现CSRF令牌验证机制的PHP代码。以下脚本生成一个令牌并将其嵌入到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>";
   }
?>

它将产生以下输出

PHP Csrf

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

广告