PHP 8.5.11 安全修复按优先级过一遍:FPM 的 IPv6 ACL 绕过该先处理
信源:PHP 8 ChangeLog — Version 8.5.11(24 Sep 2026),https://www.php.net/ChangeLog-8.php 。php.net 公告说明这是 security release,PHP 8.5 用户建议升级。
下面按“升级后先验证什么”排优先级。命令与配置片段未在本文环境实测,路径按发行版调整(Debian/Ubuntu 在 /etc/php//fpm/pool.d/,RHEL 系在 /etc/php-fpm.d/)。
优先级速览
| 级别 | 条目 | 编号 | 排这里的依据 |
|---|---|---|---|
| P0 | FPM IPv6 ACL 绕过 | CVE-2026-91768 | 一旦 FPM 走 TCP 且 allowed_clients 是唯一访问控制,绕过即等于任意来源可发 FastCGI 请求 |
| P0 | OpenSSL 通配符 CN 堆溢出 | CVE-2026-91767 | 出站 TLS 客户端校验路径上的内存破坏 |
| P0 | HTTP wrapper 重定向跨域凭据泄漏 | CVE-2026-91766 | 凭据会被发到重定向后的另一主机,且常与 SSRF 叠加 |
| P0 | SOAP 未授权 DoS | CVE-2026-91765 / CVE-2025-14181 | 只要能发请求到 SoapServer::handle() 就能触发,无需认证 |
| P1 | OpenSSL SAN 不匹配回退 CN | CVE-2026-91769 | 中间人可利用“CN 对得上、SAN 是别家”的证书通过 |
| P1 | HTTP wrapper 空 Location 越界读 / convert.* NUL 越界读 | CVE-2026-93682 / CVE-2026-92842 | 越界读,边界在崩溃与信息泄露之间 |
| P2 | Phar、MySQLnd、Windows、MBString、Opcache、Intl、DOM、FPM UID/GID overflow | 见文末 | 触发条件更依赖具体用法 |
P0:FPM —— listen.allowed_clients 的 IPv6 ACL 绕过(CVE-2026-91768)
原文措辞:
Fixed GHSA-62xp-839h-2637 (IPv6 ACL bypass in FastCGI listen.allowed_clients due to partial address comparison). (CVE-2026-91768)
先确认你的部署形态,因为这条指令的生效条件很窄:
- 该指令只在 FPM 以 TCP 监听(
listen = 127.0.0.1:9000或0.0.0.0:9000)并设置listen.allowed_clients时生效;用 unix socket 监听时该指令无效。 - 典型用法是“nginx 和应用在同一台机器”→ 只允许
127.0.0.1;或“nginx 在另一台机器”→ 只允许 nginx 的内网 IP。
官方对原因的措辞是 “partial address comparison”:地址比较只比对了部分(前缀)。IPv6 地址写法多样(压缩写法、IPv4-mapped ::ffff:127.0.0.1、zone id),比较逻辑不严会导致本不该通过的地址被判为允许。
结论方向:如果你的 FPM 走 TCP 且依赖 allowed_clients 做唯一访问控制,这条要优先;如果走 unix socket 或上游已有网络隔离(安全组/防火墙/iptables 只放行 nginx),风险较低但升级仍需做。
可执行的核查:
grep -r "listen" /etc/php/*/fpm/pool.d/
php-fpm -tt 2>&1 | head
ss -lntp | grep 9000
curl -s --unix-socket /run/php/php8.5-fpm.sock http://localhost/status # 若开了 status
收紧配置示例:
; pool.d/www.conf
listen = 127.0.0.1:9000
listen.allowed_clients = 127.0.0.1
跨机场景改用 unix socket 或加防火墙(示例网段按实际替换):
iptables -A INPUT -p tcp --dport 9000 -s 10.0.0.5 -j ACCEPT
iptables -A INPUT -p tcp --dport 9000 -j DROP
额外的防线:FPM 只监听 127.0.0.1 或 unix socket;对 0.0.0.0 监听的实例加防火墙;status/ping 页面单独限制来源。
P0:OpenSSL 通配符 CN 堆溢出(CVE-2026-91767)
Fixed GHSA-xr7j-rvgx-xq5p (Heap buffer overflow in php_openssl_matches_wildcard_name() on crafted server certificate wildcard CN). (CVE-2026-91767)
触发位置在 TLS 客户端证书名校验:对端返回构造过的 wildcard CN 时,php_openssl_matches_wildcard_name() 发生堆缓冲区溢出。也就是说,只要 PHP 作为客户端去连一个可控或已被攻陷的 HTTPS 服务,就可能命中。
检查方式主要是升级后回归:拉一张对端证书看 CN/SAN,确认代码路径仍走 openssl 扩展而非 curl 扩展(两者校验实现不同):
openssl s_client -connect host:443 -servername host Fixed GHSA-fpwc-w8rq-cr92 (Cross-origin credential leak in HTTP stream wrapper redirects). (CVE-2026-91766)
场景:`file_get_contents` / `fopen` 带 `Authorization` 或 `Cookie` 的 stream context,遇到 3xx 跳转到另一主机,凭据被继续发送到新主机。
排查代码里所有 stream context 带 header 的 http 请求,特别是把用户提供的 URL 直接丢给 `file_get_contents` 的地方(SSRF + 凭据外泄叠加):
```bash
grep -rn --include='*.php' -E "stream_context_create|file_get_contents\(['\"]https?://" /var/www
升级之外可加的临时约束:对不受信任 URL 关掉自动跟随,自行校验 host 后再发:
$ctx = stream_context_create([
'http' => [
'header' => "Authorization: Bearer {$token}\r\n",
'follow_location' => 0,
'max_redirects' => 0,
],
]);
P0:SOAP 未授权 DoS(CVE-2026-91765、CVE-2025-14181)
Fixed GHSA-rgrp-mwpx-f6rm (Unbounded recursion in server-side cleanup_xml_node()). (CVE-2026-91765)
Fixed GHSA-cj93-vc83-wgqv (Integer overflow to buffer overflow in SOAP HTTP parsing). (CVE-2025-14181)
只要能发一个请求到 SoapServer::handle() 就能触发,不需要认证。缓解手段是 WSDL 模式加 IP 白名单 / 反代限流;不用 SOAP 的关掉扩展。
php -m | grep -i soap
nginx 侧限流 + 白名单:
limit_req_zone $binary_remote_addr zone=soap:10m rate=10r/s;
location /soap/ {
limit_req zone=soap burst=20 nodelay;
allow 10.0.0.0/8;
deny all;
include fastcgi_params;
fastcgi_pass unix:/run/php/php8.5-fpm.sock;
}
P1:OpenSSL SAN 不匹配后回退 CN(CVE-2026-91769)
Fixed GHSA-vvx9-73fr-5jjx (TLS hostname verification falls back to CN after SAN mismatch). (CVE-2026-91769)
现代浏览器早已忽略 CN,只看 SAN。PHP 的 stream/curl 走 openssl 扩展时,若证书 SAN 不匹配但 CN 匹配,旧行为会接受——这会让中间人用“CN 对得上、SAN 是别家”的证书通过。
影响面:出站 HTTPS(file_get_contents('https://...')、fsockopen + ssl、SoapClient 的 https、以及所有用 php_stream 的库),以及自签/内网 CA 场景。
检查:升级后看对端 SAN 是否覆盖实际访问的域名:
openssl s_client -connect host:443 -servername host Fixed GHSA-7875-c8px-7q5f (Out-of-bounds read in the HTTP stream wrapper when following a redirect with an empty Location header). (CVE-2026-93682)
> Fixed GHSA-88hq-2827-7pg6 (Out-of-bounds read in convert.* stream filters when line-break-chars contains NUL). (CVE-2026-92842)
前者在跟随重定向且 `Location` 为空时触发,后者在 `convert.*` 过滤器参数 `line-break-chars` 含 NUL 时触发。都属于越界读,实际影响取决于进程崩溃还是把相邻内存读出。
---
## P2:其余值得注意的条目
- **Phar**:GHSA-j3wh-g957-2m85(Integer overflow in `phar_tar_number()` allowing TAR archive entry injection),CVE-2026-6103。
- **MySQLnd**:GHSA-r6x9-5r99-36j7(Various packet overreads in mysqlnd wire protocol),CVE-2025-1218。
- **Windows**:GHSA-9f67-6fw4-hpfp(Reserved device names are not rejected before file and stream I/O),CVE-2026-17545。
- **FPM**:GH-19320(FPM UID and GID overflow)。
- **MBString**:`mb_ereg_replace()` 在 `\k` 反向引用没有闭合分隔符时,可能输出 NUL 或越界字节。
- **Opcache**:ZTS 下 `opcache.protect_memory` 的竞争;tracing JIT 若干崩溃。
- **Intl**:`grapheme_strpos`/`grapheme_strrpos` 空 needle 返回 UTF-16 偏移而不是 grapheme 偏移;`NumberFormatter` 解析偏移用 UTF-16 位置(GH-23094);`grapheme_str_split` 把 `UBRK_DONE` 当 byte index。
- **DOM**:`getElementsByClassName` 等 node list 缓存在 `className`/`classList` 写入和属性删除后过期;多个 UAF。
---
## 升级后确认版本
```bash
php -v
php-fpm -v
php -m | grep -Ei 'soap|openssl|phar|mysqli'
php -v 应显示 8.5.11。生产机上 CLI 与 FPM 可能是两个包,两边都要核对;FPM 改完配置记得 php-fpm -tt 校验后 reload。