综合 PHP 8.5.11 安全修复按优先级过一遍:FPM 的 IPv6 ACL 绕过该先处理

2026-10-20 21:04:01

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/)。

优先级速览

级别条目编号排这里的依据
P0FPM IPv6 ACL 绕过CVE-2026-91768一旦 FPM 走 TCP 且 allowed_clients 是唯一访问控制,绕过即等于任意来源可发 FastCGI 请求
P0OpenSSL 通配符 CN 堆溢出CVE-2026-91767出站 TLS 客户端校验路径上的内存破坏
P0HTTP wrapper 重定向跨域凭据泄漏CVE-2026-91766凭据会被发到重定向后的另一主机,且常与 SSRF 叠加
P0SOAP 未授权 DoSCVE-2026-91765 / CVE-2025-14181只要能发请求到 SoapServer::handle() 就能触发,无需认证
P1OpenSSL SAN 不匹配回退 CNCVE-2026-91769中间人可利用“CN 对得上、SAN 是别家”的证书通过
P1HTTP wrapper 空 Location 越界读 / convert.* NUL 越界读CVE-2026-93682 / CVE-2026-92842越界读,边界在崩溃与信息泄露之间
P2Phar、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。

复制全文 生成海报 PHP 安全运维 php-fpm 升级

推荐文章

程序员茄子在线接单