一、先搞清楚:漏洞从哪来
PHP 站点面临的安全问题通常分两类,修复手段完全不同:
- 解释器自身漏洞:PHP 版本停止维护后曝出的 CVE(反序列化、堆溢出、类型混淆等)。这类只能靠升级 PHP 版本修复,改代码没用。
- 应用层代码漏洞:业务代码对用户输入处理不当导致的注入、包含、反序列化等问题,靠代码加固修复。
一次完整的修复通常两者都要做:先把解释器升到受支持版本,再排查应用层代码。
二、第一步:确认版本并升级到受支持版本
先看当前版本(CLI 与 FPM 可能是两个版本,都要查):
php -v
php-fpm -v # 或用 php-fpm8.3 -v 看具体 SAPI
php -m | grep -i xml # 顺便确认加载的扩展
对照 PHP 官方安全支持周期:停止安全支持的版本(如早已 EOL 的 7.4 及更早、8.0 等)不会再收到补丁。修复官方已知漏洞唯一可靠的方式是升级到当前受支持的稳定版(如 8.2 / 8.3),并尽快安装发行版的安全更新。不要指望“打补丁”能替代升级。
Debian / Ubuntu 上的一条线升级示例:
sudo apt update
sudo apt upgrade php php-cli php-fpm php-common php-xml php-mysql
sudo systemctl restart php8.3-fpm
sudo systemctl restart nginx
升级后务必用 php -v 再次确认 SAPI 版本已切换,很多“升级了却没生效”是 FPM 没重启或站点仍走旧 socket 导致的。
三、常见应用层漏洞与修复
1. 反序列化漏洞(最危险)
对不可信数据调用 unserialize() 会触发 __destruct / __wakeup / __toString 中的危险逻辑,构造出 POP 链实现 RCE。
❌ 危险写法:
$data = unserialize($_COOKIE['user']);
✅ 修复:优先用 JSON,必须反序列化时限制类白名单:
// 首选:用 JSON 替代
$data = json_decode($_COOKIE['user'], true);
// 必须反序列化时,禁止任意类实例化
$data = unserialize($raw, ['allowed_classes' => [User::class]]);
2. 文件包含 LFI / RFI
❌ 危险:让用户控制的变量直接参与包含路径。
include 'pages/' . $_GET['page'] . '.php';
✅ 修复:严格白名单,绝不允许路径穿越。
$allowed = ['home', 'about', 'contact'];
$page = $_GET['page'] ?? 'home';
if (!in_array($page, $allowed, true)) {
http_response_code(403);
exit;
}
include "pages/{$page}.php";
3. 命令注入
// ❌ 危险:输入直接拼进 shell
system('ping -c 1 ' . $_GET['host']);
// ✅ 修复:转义参数,最好用不落 shell 的方式
system('ping -c 1 ' . escapeshellarg($_GET['host']));
更彻底的做法是避免 exec/system,改用 PHP 原生实现(如用 fsockopen 探测端口)
4. SQL 注入
// ❌ 危险:拼接
$db->query("SELECT * FROM u WHERE id = {$_GET['id']}");
// ✅ 修复:预编译 + 强类型
$stmt = $pdo->prepare('SELECT * FROM u WHERE id = ?');
$stmt->execute([(int) $_GET['id']]);
5. XXE 与 SSRF(简述)
XXE:加载外部 XML 前禁用外部实体,并禁止网络实体:
libxml_disable_entity_loader(true);
$dom = new DOMDocument();
$dom->loadXML($xml, LIBXML_NONET);
SSRF:校验目标地址,禁止访问内网与云元数据地址(如 169.254.169.254),对 DNS 重绑定也要做二次校验。
四、php.ini 加固清单
display_errors = Off ; 生产环境绝不暴露错误
log_errors = On
expose_php = Off ; 隐藏 X-Powered-By 中的 PHP 版本
allow_url_fopen = Off ; 非必要关闭
allow_url_include = Off ; 杜绝远程文件包含
disable_functions = exec,passthru,shell_exec,system,proc_open,popen,pcntl_exec
session.cookie_secure = On
session.cookie_httponly = On
session.cookie_samesite = Lax
disable_functions 按业务裁剪,不要一键照抄导致正常功能报错。
五、紧急修复流程
- 对代码与数据库做快照 / 备份;
- 升级 PHP 到受支持版本并重启对应 SAPI;
- 用静态分析(PHPStan / Psalm)或安全扫描器定位应用层风险点;
- 按第三节逐个修复,并补充对应单元测试;
- 灰度发布 + 回归验证;
- 在入口层接入 WAF 与异常告警,保留审计日志。
六、上线前验证清单
php -v为受支持版本;- php.ini 关键项(上节)符合要求;
- 静态扫描无高危项;
- 外网无法访问
phpinfo()、.git、备份与上传目录中的脚本。
安全是持续过程。把版本升级纳入常规运维节奏,对所有用户输入坚持“白名单 + 参数化 + 最小权限”三原则,能挡掉绝大多数 PHP 相关入侵。