PHP:同一页面多表单使用CSRF Token重复生成问题解决方案
解决同一页面多表单共用CSRF Token的问题
问题出在你的csrf_token_tag()函数每次调用都会执行create_csrf_token(),而这个函数每次都会生成新的Token并覆盖session中的值。这样第一个表单的Token是第一次生成的,第二个表单用的是第二次生成的,而session里只保留了最后一次的Token,提交第一个表单时自然会验证失败。
修改后的完整代码
<?php session_start(); // 必须在所有session操作前开启session // 生成随机CSRF Token function csrf_token() { return bin2hex(random_bytes(35)); } // 获取或创建有效的CSRF Token(有效期设为1小时,可按需调整) function get_csrf_token() { $expiration = 3600; // Token有效期,单位:秒 // 检查session中是否存在有效Token if (isset($_SESSION['csrf_token']) && isset($_SESSION['csrf_token_time']) && (time() - $_SESSION['csrf_token_time']) < $expiration) { return $_SESSION['csrf_token']; } // 没有有效Token时,生成新的并存入session $token = csrf_token(); $_SESSION['csrf_token'] = $token; $_SESSION['csrf_token_time'] = time(); return $token; } // 生成CSRF Token的隐藏输入标签 function csrf_token_tag() { $token = get_csrf_token(); // 复用已有Token,而非每次生成新的 return '<input type="hidden" name="csrf_token" value="' . $token . '">'; } // 生成一次Token标签,或者直接在表单里调用csrf_token_tag()都可以 $csrf_token = csrf_token_tag(); ?> <form action="" method="post"> <!-- 表单1内容 --> <?= $csrf_token; ?> <button type="submit">提交表单1</button> </form> <form action="" method="post"> <!-- 表单2内容 --> <?= csrf_token_tag(); ?> <!-- 这里直接调用函数也会返回同一个Token --> <button type="submit">提交表单2</button> </form>
表单提交后的验证逻辑
不管提交哪个表单,验证逻辑都是一样的,确保Token匹配且未过期:
if ($_SERVER['REQUEST_METHOD'] === 'POST') { // 检查Token是否存在 if (!isset($_POST['csrf_token']) || !isset($_SESSION['csrf_token'])) { die("CSRF验证失败"); } $expiration = 3600; // 验证Token是否匹配且未过期 if ($_POST['csrf_token'] !== $_SESSION['csrf_token'] || (time() - $_SESSION['csrf_token_time']) >= $expiration) { die("CSRF验证失败"); } // 验证通过,处理你的表单业务逻辑 echo "表单提交成功!"; }
关键说明
get_csrf_token()函数:核心逻辑是优先复用session中已有的有效Token,只有在Token不存在或过期时才生成新的,这样同一页面的所有表单都会使用同一个Token。session_start():必须在所有session操作之前调用,否则无法读取或写入session中的Token。- 有效期设置:你可以根据需求调整
$expiration的值,比如设置为1800秒(30分钟),平衡安全性和用户体验。
内容的提问来源于stack exchange,提问作者yikemop651
相关产品推荐
相关产品推荐

