面板、Docker、FrankenPHP、虚拟主机:PHP 紧急更新的四种升法
2026 年 10 月 21 日晚,PHP 官方发了一轮紧急安全更新:8.5.12、8.4.27、8.3.36、8.2.35 四个补丁版同时落地,修的是两个能让未登录攻击者直接在你服务器上执行代码的洞(CVE-2026-109618、CVE-2026-109619,CVSS v4.0 都是 9.2 分)。有媒体给这两个洞起了个外号叫 PHP2Shell,搜相关讨论时用得上。
不管你的 PHP 是面板装的、命令行装的还是跑在 Docker 里,只要在对外 serve 请求,就都在这轮公告的打击面里。这篇只解决一件事:半小时内确认自己中没中,然后把它升上去。
这轮安全公告各处都在转,我对号入座:手上正好有个站跑着 PHP。当晚查了版本、升了上去——这篇写的就是那条路。
一、这两个洞打的是 PHP 本身
先看两个洞各自是怎么回事,说人话版:
- CVE-2026-109618:PHP 在处理内存耗尽(OOM)时会用一个长跳转直接退出当前请求上下文,而这块请求内存还没完全初始化好,清理例程把它当成有效数据继续处理——内存破坏,攻击者顺着这个执行任意代码。
- CVE-2026-109619:常驻的 PHP 工作进程处理完一个请求后,上一轮请求的部分全局状态(错误、会话、对象、扩展状态)没有完全清零,下一个请求碰到的是已经释放掉的内存。攻击者在同一个进程的前后两个请求里分饰生产者和消费者,把堆布局布置好,就能打出未授权的释放后使用。
洞是安全公司 Wiz 发现的。三个判断跟个人站长直接相关:
- 洞在 PHP 运行时,不在你的 CMS 和代码里。WordPress、Drupal、Joomla、织梦这些都不用跟着发版,要动的是它们脚底下跑的 PHP。
- 请求没进你的业务代码就能被触发。 官方明确说 Apache mod_php 这种部署方式风险最高,已有演示级别的利用,代码执行之前就被打中。所以"我代码写得干净""我装了安全插件"在这两个洞面前都不构成防线。
- 打穿之后拿到的是 Web 工作进程账户的权限,不是 root。但攻击全程不需要登录,而你的站天天挂在网上——这已经够了。
二、先查:你的 PHP 在不在裸奔区间
判断规则只有一条:版本号大于等于上面给的修复版,这次就没事;低于修复版,现在就是裸奔状态。
四个在支持期内的分支,修复版分别是:
- PHP 8.5 → 升到 8.5.12
- PHP 8.4 → 升到 8.4.27
- PHP 8.3 → 升到 8.3.36
- PHP 8.2 → 升到 8.2.35
- PHP 8.1 及更早 → 已经不在官方支持版本表里,这轮不会有你的补丁
查版本的方式,对照你的部署方式选一个:
面板部署(宝塔、1Panel):进软件商店,找到 PHP 那一项,版本号直接写在上面。多版本共存的面板,每个安装的版本都要看一遍,站点用的可能不是最新的那个。
SSH 直装:
php -v
第一行就是。如果服务器上跑了多个版本,which php 指向的那个不一定是网站实际用的,以 Web server 配置里加载的为准。
Docker 部署:
sudo docker ps
sudo docker exec 容器名 php -v
FrankenPHP 容器用 frankenphp version,FrankenPHP 版本和 PHP 版本会一起打出来,一眼看全。
虚拟主机、共享主机(没有 shell):写一个只含 <?php phpinfo(); 的文件传到 web 目录,浏览器打开看最上面的版本号,看完立刻删——phpinfo 会把服务器环境信息全都摊开,这东西挂在线上本身就是个情报来源。
查到版本后分三种情况:已经在修复版之上,这篇剩下的当背景知识读;低于修复版,往下走第三节;8.1 及更早,没有补丁可打,借这次机会直接换线(8.2 年底也会断粮,见第五节)。
三、升:四种部署各怎么动
面板部署
软件商店里安装目标版本的 PHP,然后把网站的 PHP 版本切换过去,确认站点前台后台都正常之后,旧版本没有站用了再卸载。具体菜单各面板叫法不一样,以你手上那块面板的实际操作为准。
Docker 官方镜像
compose 文件里把镜像 tag 从浮动的小版本 pin 到修复版,比如 php:8.5-fpm 改成 php:8.5.12-fpm。官方这次在公告当天就把 8.5.12 的全套 tag 发齐了:fpm、apache、cli、zts、alpine、bookworm 各个变体都有。
改完 docker compose up -d 重建容器,再用第二节的命令验一遍版本。
FrankenPHP
分两种。用官方镜像的,把 Dockerfile 的 FROM 换成带修复版 PHP 的 tag。官方在公告当天就重建了镜像,dunglas/frankenphp:1.13.2-php8.5-trixie(2026-10-21 重建)内置的就是 PHP 8.5.12。1.13 这一系自身还修了 5 个漏洞,内置的 Caddy 也从 2.11.4 升到了 2.11.7,属于顺带的收益。
在官方镜像上自己加过东西的(自建镜像),只用改 FROM 那一行,重新 build。拿一台 FrankenPHP 主机走一遍完整流程(下面的 服务名 是你 compose.yml 里跑 FrankenPHP 的那个服务,可能叫 caddy、frankenphp、web,按你文件里的实际名字写):
# 0. 先给现在跑得好的镜像打个 tag,出事秒回滚
sudo docker tag 你的镜像名:latest 你的镜像名:bak-20261022
# 1. Dockerfile 里 FROM 改为:
# dunglas/frankenphp:1.13.2-php8.5-trixie
# 2. 重建镜像、换容器
cd 你的项目目录 && sudo docker compose build 服务名
sudo docker compose up -d 服务名
# 3. 验证容器里的版本
sudo docker exec 容器名 frankenphp version
输出里应该看到 PHP 8.5.12。之后把每个站点前台点一遍,确认没被这次重建带坏。
apt / yum 直装
先更新包索引再装新版本:
sudo apt update && sudo apt install php8.5
系统自带源里的 PHP 版本通常偏旧且只有一个,想多版本并存、想及时拿到补丁,一般用的是(Debian/Ubuntu)或 Remi(RHEL 系)这类第三方源。装好在 Web server 配置里把 PHP 切到新版本,重启服务。以源里实际提供的版本号为准。
虚拟主机用户
PHP 版本不在你手里,在主机的控制面板里。正确动作是开工单,直接问两句话:什么时候升到修复版(8.5.12 / 8.4.27 / 8.3.36 / 8.2.35,按你的分支报一个)?不给升的话我迁走。对方打太极的,这次就是个换主机理由——未授权 RCE 不是可以慢慢等的洞。
四、没有"先挡一挡"这回事
官方在 8.3.36 的发布公告里把话写死了:没有完整的缓解措施,更新是唯一安全的选择(There are no complete mitigations, updating is the only safe choice)。这轮公告没有给 WAF 规则,没有给配置项开关,什么 disable_functions 都不在这次的建议里。
所以看到"先加条规则顶着"的教程,知道那不是官方方案,顶多算心理安慰。
真要做事,就是把第三节走完。两个不花钱的收尾检查可以做:站前面有没有 CDN 或 WAF 类的代理挡着(有总比裸奔强,但这不算本次的缓解措施);翻一下最近几天的访问日志,看有没有异常的大批量 POST——这是事后看有没有人来过,不是防护。
五、升完顺手做的三件事
- 借这次把版本线捋直。8.1 已经没补丁了,必须换;8.2 的安全支持 2026 年 12 月 31 日到期,还有两个多月,能升到 8.3 / 8.4 的顺手升。升级本身照老纪律来:先备份、挑低峰时段、留好退路,跟升系统一个道理。
- Docker 用户立个习惯:镜像 tag 图新不图表准。浮动 tag(
8.5-fpm)拉到什么是什么,pin 到带小版本号的 tag(8.5.12-fpm)才知道自己跑的是什么。官方这次的 8.5.12 全套 tag 是现成的。 - 收藏 PHP 官方公告入口。这个页面,每次紧急更新都从这发,比任何二手通报都快。
一句话:两个 9.2 分的未登录 RCE 摆在那,查版本五分钟,升级半小时,这笔时间别省。
- 点赞
- 收藏
- 关注作者
评论(0)