通过 AJAX 调用提交表单时防止 CSRF

信息安全 Web应用程序 应用安全 php csrf 阿贾克斯
2021-08-20 06:43:49

我在所有表单上都使用了反 CSRF 令牌来防止 CSRF 攻击。此外,令牌被保存在 $_COOKIE 变量中,以验证我从表单中获得的值。每次加载表单时我都会重置令牌。

但是有一些表单使用 $.post,即 AJAX 提交并获得 JSON 响应。

由于使用了 AJAX,因此未设置 $_COOKIE 变量。

有解决方法还是我做错了什么?

编辑:添加客户端和服务器端代码示例

客户端:

<?php
$tokenVal = md5(uniqid(mt_rand(), true));
setcookie ("token", $tokenVal);
?>
<form action="target.php" method="post" name="abc">
<input type="text" name="city" id="city" value="abc" size="25" maxlength="10">
<input type="hidden" name="csrf" value="<?php echo $tokenVal; ?>">
<a class="cssButton buttonColor right" id="billToSubmit">Save</a>
</form>

服务器端:

if($_POST['csrf'] == $_COOKIE['token']) {
//process further
} else {
die("Invalid form source")
}

表单正在使用 $.post 提交。我面临的问题是 $_POST['csrf'] 永远不等于 $_COOKIE['token']!

4个回答

假设 JavaScript 可以使用 CSRF 令牌,您可以使用setRequestHeader手动附加请求令牌并修改您的服务器以在 cookie 标头中查找请求令牌,或者在您提供的标头中查找应可通过 XHR 访问的请求。

大多数 Javascript 框架在 ing 请求时都会添加一个特定的标头POST,例如X-Requested-With: AJAX. 理论上,在后端,您可以检查此标头是否存在,以确保您的表单是通过 AJAX 提交的(攻击者不应让第三方向表单提交添加自定义标头)。由于 AJAX 请求只能来自同一个域,因此您应该免受 CSRF 攻击。

但是 已经发现,在存在某些浏览器插件组合的情况下,攻击者实际上有可能制作带有自定义标头的请求。这使得上述方法不那么合理。今天首选的保护是将 CSRF 令牌传递给客户端,即使是 AJAX 提交也是如此。例如,您仍然可以将其添加到隐藏字段中,然后使用 javascript 读取它。

编辑:关于$_COOKIE$未在 AJAX 请求中设置变量,我不明白你的意思。您实际上可以在 AJAX 请求中设置 cookie,即使是普通的 cookie 也会被保留,只要它们不是 http-only 的。

这是一种有效的 CSRF 保护形式,因为攻击者不会知道那里的 cookie 的值,因为攻击者不会有令牌发布变量的有效值。这种方法不需要每个用户的状态,这是一个好处。

CSRF 预防备忘单是一个很好的资源。

如果您使用 cookie 来存储(和检索)CSRF 令牌,那并不能真正缓解 CSRF 漏洞 更正:正如评论中所澄清的那样,这条线不适用于 Gaurav 使用 CSRF 令牌的方式。

与其制定自己的 CSRF 预防方案,不如使用PHP CSRF Guard之类的东西