PHP 8.3.36 是修复远程代码执行漏洞的安全版本,不解决变量覆盖问题;变量覆盖源于 extract()、parse_str() 等函数误用,需检查参数与上下文并采用 EXTR_SKIP 或前缀隔离等安全实践。

PHP 8.3.36 本身是修复版本,不是漏洞版本。你不需要“修复 PHP 8.3.36 的变量覆盖漏洞”,而是要确认:你当前运行的是否真是 8.3.36,以及业务代码里是否还存在 extract()、parse_str() 等函数引发的变量覆盖风险。
变量覆盖漏洞从来不是 PHP 版本自身的“bug”,而是开发者误用函数导致的逻辑缺陷。而 8.3.36 修复的是两个 远程代码执行(RCE)漏洞(CVE-2026-109618 / CVE-2026-109619),和变量覆盖无关。
extract() 调用是否安全?看参数和上下文
extract() 是变量覆盖最常见入口,但它的风险完全取决于你怎么用:
-
extract($_GET)或extract($_REQUEST)→ 危险,直接覆盖已有变量 -
extract($_POST, EXTR_SKIP)→ 相对可控,跳过已存在变量 -
extract($data, EXTR_PREFIX_ALL, 'input')→ 安全,所有键都加前缀,如$name变成$input_name
常见错误现象:
立即学习“PHP免费学习笔记(深入)”;
- 后台登录绕过:
$is_admin=false被?is_admin=1覆盖后直接进入管理页 - 配置文件路径被篡改:
$config_file='/etc/app/config.php'被?config_file=/etc/passwd覆盖,后续配合file_get_contents($config_file)导致任意文件读取
实操建议:
修复 Core bailout 状态损坏安全问题,以及 BZ2、DOM、PDO、Opcache/JIT 内存与执行错误,改进 Unicode 字素处理、URL 解析、TLS 流状态、信号分发及会话错误处理。
extract(,逐行检查第二个参数
- 禁止无参数或仅传数组的写法;必须显式指定 EXTR_SKIP 或 EXTR_PREFIX_ALL
- 替代方案更推荐:用 array_key_exists() + 显式赋值,比如 $user = $_GET['user'] ?? null;
parse_str() 没传第二个参数?立刻改
parse_str() 在没提供目标数组时,会把解析结果直接注入当前作用域:
// 危险!等价于 extract()
parse_str("name=admin&role=user");
// $name 和 $role 现在是全局变量,可能覆盖已有变量实操建议:
- 所有parse_str() 调用必须传入第二个参数(数组变量名):
$parsed = []; parse_str($input, $parsed); // 安全,结果在 $parsed 里- 如果输入来自用户(如
$_GET['query']),先校验格式,再解析
- 避免解析后直接 extract($parsed) —— 这等于套娃危险
为什么升级到 8.3.36 不能解决你的变量覆盖问题?
因为:
-
8.3.36修复的是 PHP 内存管理阶段的 RCE 漏洞(影响请求初始化/异常清理路径),与extract()行为无关 - 即使你用的是
8.3.36,只要代码里还有extract($_GET),变量覆盖漏洞就依然存在 - 同样,
8.5.12、8.4.27也只修复底层 RCE,不改变函数语义
真正要做的事:
- 运行php -v 确认实际版本(别只信包管理器显示的版本号)
- 检查所有用户输入进入 extract()、parse_str()、mb_parse_str() 的路径
- 把动态变量赋值(如 $$key = $val)全部替换成白名单映射
变量覆盖的隐蔽性在于:它不报错、不中断流程,只悄悄改掉关键判断变量。最容易被忽略的,是那些“先赋默认值,再 extract()”的代码块——你以为覆盖不了,其实只是顺序错了。


















