如果今天无法升级
临时缓解措施
在推送升级期间,这些措施可以降低特定已知攻击路径的风险。它们都不完整,有些还有明显代价。上线前请先测试。
最后核实 2026-10-22
不存在能完全修复的配置
两份 PHP 官方公告都明确这样说。用它们争取几小时或几天,而不是几周。修复指南 →
各项措施的作用
| 措施 | 效果 | CVE | 代价 / 副作用 |
|---|---|---|---|
首选 | 公告中最主要的配置缓解措施。去掉 PHP 自身的 OOM 中断,而大多数攻击路径都依赖它。 | 两者 | 改由操作系统杀掉失控的 worker,会中断请求。没有 cgroup 上限的话,单个请求就可能耗尽整台主机的内存。 |
部分有效 | 可挡住已证实的会话路径,“但挡不住其他变种”(php.net)。必须在 php.ini、FPM 池或服务器配置里设置——不能用 .user.ini 或 ini_set()。 | …619 | 依赖它的上传进度条会失效(很少见)。如果用不到,打补丁后也建议保持关闭。 |
部分有效 | 只挡住已证实的致命错误回溯路径——这是 CVE-2026-109619 演示中最直接的情形。 | …619 | 致命错误将不再包含回溯信息。 |
调低 部分有效 | 减少攻击者在 multipart 解析阶段(应用运行之前)能制造的内存压力。php.net 建议:不需要上传文件时设 8M,需要时设 32M。 | …618 | 也会限制上传——请测试正常的上传流程。 |
限制输入: 部分有效 | 限制解析器带来的其他内存增长。 | …618 | 大型或深层嵌套的表单可能会提交失败。 |
消除攻击者可触发的致命错误,以及按请求生效的无效 / 已弃用配置 部分有效 | 去掉 CVE-2026-109619 残留状态的来源:初始化前输出的诊断信息,以及回调、上传、导入和清理中的致命错误与超时。 | …619 | 需要投入代码和配置审查工作。 |
调低 部分有效 | 更频繁地回收 worker,让被破坏的状态存活更少的请求。公告提到的极端值是 1。 | …619 | 有实际的 CPU 和延迟代价;对单请求攻击无效。 |
限制影响 | 防止错误输出向访客泄露细节。注意:隐藏诊断信息并不能阻止 CVE-2026-109619 的触发。 | 影响面 | 生产环境无副作用。 |
用 SELinux / AppArmor 约束 PHP worker 限制影响 | 限制注入代码能执行或读取的内容。 | 影响面 | 需要编写策略;无法阻止内存泄露。 |
WAF / CDN 托管规则 部分有效 | 在边缘拦截已知的载荷特征。Cloudflare 免费版也已覆盖。 | 两者 | 攻击者已经在变形载荷;不同厂商的覆盖范围不同。 |
不要这样做
不要用 RLIMIT_AS / RLIMIT_DATA 代替 memory_limit
也就是 ulimit -v / ulimit -d、systemd 的 LimitAS= / LimitDATA=,或各种 rlimit_* 技巧。它们会让 PHP 内部的 mmap() 失败,触发的正是同一条有漏洞的 OOM 路径。请改用 cgroup 限制(MemoryMax=、容器的 --memory)。
可直接复制的配置
; /etc/php/8.3/fpm/conf.d/99-php2shell.ini (path varies)
; TEMPORARY PHP2Shell mitigations — revisit after upgrading.
; Tune every number to what your application really needs.
session.upload_progress.enabled = 0
fatal_error_backtraces = 0 ; PHP 8.5 only, ignored elsewhere
display_errors = 0
post_max_size = 8M ; php.net: 8M without uploads, 32M with
upload_max_filesize = 6M ; keep below post_max_size
max_input_nesting_level = 32 ; default 64
max_input_vars = 1000
max_file_uploads = 5 ; default 20
max_multipart_body_parts = 200; /etc/php/8.3/fpm/pool.d/www.conf (one block per pool)
; php_admin_* cannot be overridden by ini_set() in application code.
; WordPress and others call ini_set('memory_limit', ...) — a plain
; php.ini value would be silently replaced with a finite limit again.
php_admin_value[memory_limit] = -1
php_admin_flag[session.upload_progress.enabled] = off
; Recycle workers more often (performance cost — measure it)
pm.max_requests = 50# Apache + mod_php (VirtualHost or global config)
php_admin_value memory_limit -1
php_admin_flag session.upload_progress.enabled off
# 32 MiB request body cap (match post_max_size)
LimitRequestBody 33554432
# nginx in front of PHP-FPM
client_max_body_size 32m;# Cap total PHP-FPM memory with cgroup v2 (systemd's MemoryMax = memory.max)
sudo systemctl edit php8.3-fpm
# [Service]
# MemoryHigh=3G
# MemoryMax=4G
sudo systemctl restart php8.3-fpm
systemctl show php8.3-fpm -p MemoryMax
# Containers: set a memory limit on the container instead
docker run --memory=4g ...每次修改后都要重启 PHP-FPM / Apache。用 php-fpm8.3 -i | grep -E 'memory_limit|upload_progress' 确认实际生效的值——注意 -i 只读取 php.ini,看不到池级覆盖配置,所以还要在站点上检查 phpinfo()。
升级之后
- 把
memory_limit恢复为适合你应用的有限值。修复后的 PHP 会在其之上再加一个硬限制。 - 让
post_max_size明显低于内存预算,max_input_nesting_level设成实际需要的值。 - 如果用不到,就保持
session.upload_progress.enabled = 0。攻击面更小,没有代价。 - 把
pm.max_requests恢复为平时的值。 - 可选:
expose_php = 0可以向扫描器隐藏版本号。这属于安全卫生,不是修复。