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

PHP刷新页面时CSRF Token每次新增2个而非1个的问题排查

问题根因

你的getToken()函数本身没有语法错误,每次脚本执行时会固定生成1个新Token写入Session。刷新页面新增2个Token的核心原因是单次页面访问过程中,你的PHP脚本被触发执行了2次,多出来的Token完全是额外请求导致的。

常见触发额外请求的场景:

  • 浏览器自动请求站点favicon图标:如果你的项目没有提供favicon文件,且Web服务器配置了所有请求都重写到PHP入口文件(单入口框架/路由的通用配置),favicon请求会完整执行一遍PHP业务逻辑,额外生成1个Token
  • 页面存在空地址资源标签:例如<img src="">、<script src="">、<link href="">这类属性为空的标签,浏览器会默认将空地址解析为当前页面地址,自动发起一次额外的同路径GET请求
  • 浏览器插件/开发者工具自动发起的请求:部分密码管理、广告拦截类插件,或是开启了DevTools的资源预加载功能,会在主页面请求外额外发起一次同地址探测请求

你可以在脚本最顶部加入临时调试日志,快速确认额外请求来源:

// 调试用,记录所有触发脚本执行的请求
file_put_contents(
    './request_debug.log',
    sprintf("[%s] URI: %s | UA: %s\n", date('Y-m-d H:i:s'), $_SERVER['REQUEST_URI'], $_SERVER['HTTP_USER_AGENT']),
    FILE_APPEND
);

刷新一次页面后查看日志,就能看到同一时间段内存在2条请求记录,对应2次Token生成行为。

修复方案

第一步:拦截无效额外请求

  • 配置Web服务器直接拦截favicon请求,不要让它走PHP业务逻辑,Nginx参考配置:
location = /favicon.ico {
    access_log off;
    log_not_found off;
    return 204;
}

如果使用Apache,可以在.htaccess中加入规则:

<Files "favicon.ico">
    Require all denied
</Files>
  • 检查页面源码,删除所有src/href属性为空的资源标签
  • 可以通过请求头字段过滤非主文档请求:主页面请求的Sec-Fetch-Dest头值为document,静态资源、异步请求的该字段值不同,可在业务入口判断,非主文档请求不执行Session初始化和Token生成逻辑

第二步:优化CSRF Token生成逻辑

你当前的Token存储逻辑本身存在设计缺陷:即使没有额外请求,每次页面刷新都会永久留存一个历史Token,会导致Session体积无限膨胀。
常规CSRF防护不需要存储大量历史Token,用户会话有效期内单个有效Token即可满足需求,修改后的代码参考:

function getToken() {
    // 已存在有效Token时直接返回,不重复生成
    if (isset($_SESSION['csrf_token']) && is_string($_SESSION['csrf_token']) && strlen($_SESSION['csrf_token']) === 64) {
        return $_SESSION['csrf_token'];
    }
    $token = bin2hex(random_bytes(32));
    $_SESSION['csrf_token'] = $token;
    return $token;
}

$token = getToken();
var_dump($_SESSION);

如果你需要支持多标签页同时提交表单的多Token场景,建议给每个Token加上过期时间戳,每次生成新Token时自动清理超过预设有效期(比如1小时)的旧Token,避免无效数据堆积。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 01:57:23