首字母缩略词“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 应用程序可以相信已按照正常工作流程从预期来源收到请求。
实施 CSRF 的步骤
在 PHP 中实现 CSRF 令牌保护的步骤如下 -
- 通过启动新 session 来启动脚本。
- 生成随机字符的令牌。您可以使用 PHP 提供的几个内置函数中的任何一个来生成随机字符串。让我们使用 md5() 函数来获取生成唯一随机字符串的 uniqueid() 函数的哈希值。
- 在要提供给用户提交数据的 HTML 表单中,包含一个隐藏文件,其值作为上述步骤中生成的随机标记。
- 然后,服务器会在表单提交后根据用户会话验证令牌,以消除恶意请求。
- 您还可以添加另一个 session 变量,其值为当前时间,并发送过期时间以进行验证。
例子
以下是实现 CSRF 令牌验证机制的 PHP 代码。以下脚本生成令牌并嵌入到 HTML 表单中。
<?php
session_start();
if(!isset($_SESSION["csrf_token"])) {
// 没有令牌,生成一个新的令牌
$token = md5(uniqid(rand(), true));
$_SESSION["csrf_token"] = $token;
} else {
// 重复使用令牌
$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"]) {
// 重置令牌
echo $_GET["csrf_token"] . "<br>";
echo $_SESSION["csrf_token"] . "<br>";
echo "<h3>CSRF令牌验证成功。继续采取进一步行动</h3>";
} else {
echo "<h3>CSRF令牌验证失败</h3>";
}
?>
它将产生以下输出 -
要模拟 CSRF 验证失败,请打开浏览器的 检查 工具,手动编辑 hidden 字段中的值并提交表单以查看令牌不匹配,从而导致验证失败。