Cross-Site Request Forgery in PHP | SecureFlag Security Knowledge Base
预防
PHP 不提供针对 CSRF 攻击的内置保护;开发人员必须通过检查会话令牌或使用许多经过良好测试的库和框架之一来手动实现它。
PHP
以下步骤展示了如何action.php?do=logout
使用 Synchronizer Token Pattern 保护端点免受 CSRF 攻击。
- 成功验证后,会以安全方式生成随机令牌并存储为用户的会话变量。
<?php
$_SESSION["csrf_token"] = bin2hex(random_bytes(32));
?>
- 现在,对状态更改端点的任何请求都
action.php?do=logout
必须将令牌作为 HTTP 参数传递。以下代码段显示了如何编写<a href>
标记以将令牌作为 GET 参数传递。
<a href="action.php?do=logout&csrf=<?php echo $_SESSION["csrf_token"]; ?>">
- 以下代码段显示了如何通过将令牌作为隐藏字段传递来保护表单。
<form>
<input type="hidden" name="csrf" value="<?php echo $_SESSION["csrf_token"]; ?>">
</form>
- 该文件
action.php
现在必须在执行受保护的代码之前验证csrf
与保存在用户会话中的令牌相匹配的参数。使用安全的哈希比较函数,例如 PHPhash_equals()
。
if (!empty($_REQUEST["csrf"]) && hash_equals($_REQUEST["csrf_token"], $_SESSION["csrf_token"])) {
// The token is correct, execute the functionality.
}
else {
die("Anti CSRF token is missing or wrong.");
}
OWASP CSRF 保护器
OWASP CSRF Protector 是一个独立的 php 库,用于 Web 应用程序中的 CSRF 缓解。按照项目页面上的说明进行安装。要使用它,只需包含库并调用init()
函数。
<?php
include_once __DIR__ .'/vendor/owasp/csrf-protector-php/libs/csrf/csrfprotector.php';
// Initialise CSRFGuard library
csrfProtector::init();
Symfony 框架
Symfony 表单组件默认提供自动 CSRF 保护。其他类型的资源,如常规 HTML 表单或任何其他状态更改路由,必须通过手动生成和检查 CSRF 令牌来明确保护。
考虑使用常规 HTML 表单来删除资源。首先,使用csrf_token()
Twig 函数在模板中生成一个 CSRF 令牌,并将其存储为隐藏的表单字段。
<form action="/delete" method="post">
<input type="hidden" name="token" value="{{ csrf_token('action-delete') }}"/>
</form>
然后,在控制器动作中获取 CSRF 令牌的值,并使用isCsrfTokenValid()
来检查其有效性。
public function delete(Request $request)
{
$submittedToken = $request->request->get('token');
if (!$this->isCsrfTokenValid('action-delete', $submittedToken)) {
// The token is not correct, redirect to the index.
return $this->redirectToRoute('index');
}
// The token is correct, execute the functionality.
}
参考
OWASP -跨站点请求伪造备忘单MITRE - CWE 352 OWASP - CSRF 保护器Symfony -如何实现 CSRF 保护