2026 年 10 月 22 日,阿里云发来一条安全通告。这篇文章记录了从收到告警到确认修复的完整过程。
收到告警
下午三点多,手机弹出一条阿里云短信:PHP 曝出「php2shell」远程代码执行漏洞,编号 CVE-2026-109618 与 CVE-2026-109619,建议尽快升级。
这类安全短信我通常会先做两件事:核实真伪,确认自己的版本。
第一步:先别急着操作,核实公告
短信里的 CVE 编号和漏洞名听起来都很正式,但也不能直接照着短信里的链接点。我打开了几个独立来源交叉验证:
- IPA(日本情报处理推进机构)在 10 月 22 日发布了正式安全通告
- 斯洛文尼亚 SI-CERT、北约合作网络防御中心 NCSC 都有对应条目
- 漏洞由 Wiz 研究团队发现,官方修复版本明确:8.2.35 / 8.3.36 / 8.4.27 / 8.5.12
漏洞本身是两个问题叠加:一个是 OOM 内存不足时的错误处理,另一个是请求处理中的状态残留。单独看都不算特别严重,组合起来却能实现远程代码执行(RCE),CVSS 评分 9.2。
结论:真实漏洞,需要处理。
第二步:查自己的版本
/www/server/php/82/bin/php -v
# PHP 8.2.28 → 低于 8.2.35,在受影响范围内
服务器是 2 核 2G 的阿里云 ECS,跑着宝塔面板、nginx、PHP-FPM 和 MySQL,托管着我的博客。这种情况最常见的处理方式是:直接在宝塔面板里点升级。
但我先做了一件事。
第三步:没有备份,不上服务器
交接文档里一直写着「备份目录为空」。在改动任何运行环境之前,我先把三样东西完整备份:
# 1. 数据库
mysqldump -u user -p --single-transaction --quick liuby_top | gzip > liuby_top.sql.gz
# 2. 网站文件
tar czf wordpress.tar.gz -C /www/wwwroot/liuby.top wordpress
# 3. PHP 二进制与配置
tar czf php82.tar.gz -C /www/server/php 82
其中 PHP 那 19 MB 是最关键的——如果升级失败,可以直接解压回去恢复原版本。
这一步的意义不在于“一定会出事”,而在于出事的时候你有退路。升级失败的代价是几分钟回滚,而不是重建服务器。
第四步:编译还是用预编译包

宝塔提供的 PHP 升级通常有两种形式:面板一键预编译包,或者自己拉源码编译。
我先探测了宝塔镜像站:
curl -I https://download.bt.cn/src/php-8.2.35.tar.gz
# HTTP 200 —— 官方源码存在
镜像站有源码,那就走源码编译。好处是可以完全复刻原来的编译参数,扩展一个不少。
关键动作是:升级前先记录当前的扩展清单和 configure 参数。
php -m > before.txt
php -i | grep "Configure Command"
然后使用完全相同的参数编译新版本:
./configure --prefix=/www/server/php/82 \
--enable-fpm --with-fpm-user=www --with-fpm-group=www \
--enable-mysqlnd --with-mysqli=mysqlnd --with-pdo-mysql=mysqlnd \
--enable-bcmath --enable-mbstring --enable-intl --enable-gd \
--with-curl --with-openssl --with-sodium --with-webp \
--enable-opcache ... # 其余参数照抄原版
make -j2
2 核机器上,configure 大约 4 分钟,make 大约 13 分钟。期间服务器负载会升高,但php-fpm 还在跑旧版本,网站不受影响。
第五步:装之前先验证
编译完成不等于可以直接装。我先用编译出来的二进制做了一次体检:
./sapi/cli/php -v
# PHP 8.2.35 ✓
./sapi/cli/php -m | diff - before.txt
# 无差异 ✓
确认版本对、扩展齐,才开始替换。
第六步:替换,然后立刻验证
/etc/init.d/php-fpm-82 stop # 停机开始
make install # 替换二进制
/etc/init.d/php-fpm-82 start # 停机结束
这次停机大约 2 分钟。
替换后要验证的东西比想象中多:
| 检查项 | 命令 | 结果 ||—|—|—|| CLI 版本 | php -v | 8.2.35 || 配置语法 | php-fpm -t | success || 进程状态 | ps aux \| grep php-fpm | 正常运行 || 首页 | curl -I https://站点 | 200 || 文章页 | curl -I https://站点/文章 | 200 || 搜索 | curl "https://站点/?s=test" | 200 || 错误日志 | tail error.log | 无新增错误 |
一个容易被忽略的点:扩展文件会被覆盖
make install 会重建扩展目录。如果你的 PHP 有单独编译的扩展(比如 opcache.so 是独立文件),装完之后要检查它们还在不在。
我的检查方式很朴素:
ls -la /www/server/php/82/lib/php/extensions/*/
发现 zip.so 还在,opcache.so 被新版本覆盖成了新的——这个是正常的,因为 opcache 是官方自带扩展。
事后总结
这次升级总共花了约 20 分钟,其中 17 分钟在编译,真正影响线上服务的只有 2 分钟。
几点体会:
安全通告要核实,但不要拖。 大范围曝光的漏洞,补丁发布后几小时内就会有扫描器开始批量探测。
备份是升级的一部分,不是前置条件。 很多人卡在“没备份所以不敢升”,然后一直不敢升。
用完全相同的编译参数。 这是避免“升级后某个功能突然不可用”最有效的方法。
验证要逐个检查,不能只看首页。 首页 200 不代表文章页、搜索、登录都正常。
最后提醒一句:PHP 8.1 及以前已经停止维护,这次漏洞不会给它们发补丁。如果你还在用更老的版本,问题不是“要不要升级”,而是“什么时候必须升级”。