You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHP表单CSRF Token校验实现及两token始终不匹配问题求助

问题原因排查
    1. 函数名大小写不匹配
      你定义的生成函数名为RandomToken,但在config.php中存储session时写的是randomToken(),PHP对函数名大小写敏感,此处会调用失败,session中存储的实际是null或者错误值,自然无法匹配。
    1. Session存储值和表单输出值不是同一个
      你定义的$token是RandomToken() + 换行 + Salt() + 换行的拼接值,但$_SESSION['t']里直接存的是单次randomToken()的返回值,两个值完全不同,表单输出的是$token,和session内的值对比必然不一致。
    1. 表单页面未引入config.php
      form-page.php中仅引入了../connection/cnt.php,没有引入config.php,表单里调用的$token属于未定义变量,输出的是空值或者PHP报错内容,提交后当然匹配失败。
    1. 核心逻辑顺序错误
      CSRF token的正确逻辑是:用户访问表单页时生成一次token,存入session同时输出到表单。提交校验时直接读取session中之前存的旧token和提交的值对比,你此前的旧版本代码甚至在提交校验时先重新生成token覆盖session的值,相当于拿新生成的token和用户提交的旧token比,永远不可能一致。
    1. 冗余的session_start调用
      重复调用session_start()没有必要,PHP高版本虽然不会直接报错,但如果在有输出后调用容易触发「头信息已发送」警告,反而影响功能。
修复方案

1. 修正config.php代码

<?php
ob_start();
// 全局只启动一次session即可
if (session_status() === PHP_SESSION_NONE) {
    session_start();
}

function RandomToken($length = 32){
    if(!isset($length) || intval($length) <= 8 ){
        $length = 32;
    }
    if (function_exists('random_bytes')) {
        return bin2hex(random_bytes($length));
    }
    if (function_exists('mcrypt_create_iv')) {
        return bin2hex(mcrypt_create_iv($length, MCRYPT_DEV_URANDOM));
    }
    if (function_exists('openssl_random_pseudo_bytes')) {
        return bin2hex(openssl_random_pseudo_bytes($length));
    }
    return '';
}

// 仅在访问表单页、且当前session中没有token的时候才生成新token
if (!isset($_SESSION['t'])) {
    $random = RandomToken(32);
    // 不需要多余的换行和盐,随机字符串本身已经足够安全
    $_SESSION['t'] = $random;
}
// 统一用session里的token输出到表单,保证前后一致
$token = $_SESSION['t'];
?>

2. 修正form-page.php代码

<?php
ob_start();
// 先引入config.php,自动处理session和token
include 'config.php'; // 改成你自己的config.php实际路径
include '../connection/cnt.php';

if (isset($_POST['submit'])) {
    // 直接拿session里存的旧token对比
    if (empty($_POST['csrf_token_p']) || $_SESSION['t'] !== $_POST['csrf_token_p']) {
        // 校验失败跳转
        ?>
        <script type="text/javascript">
            window.location = "p_tl.php?edit=N";
        </script>
        <?php
        exit;
    }
    // 校验通过,销毁当前token防止重复提交(可选,根据业务需求决定)
    unset($_SESSION['t']);
    // 这里写你的业务逻辑
}
?>

<form id="validate" action="p_tl.php" method="post" class="needs-validation" novalidate>
    <!-- 建议改成hidden类型,不需要显示给用户 -->
    <input type="hidden" name="csrf_token_p" value="<?php echo htmlspecialchars($token); ?>" class="form-control" id="validationCustom01" required>
    <input
        style="background-color: #9da1a4;color: #fff;"
        name="submit"
        value="modifica"
        class="btn  btn-sm"
        type="submit">
</form>

内容的提问来源于stack exchange,提问作者user15775524

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 03:36:02