如果今天无法升级

临时缓解措施

在推送升级期间,这些措施可以降低特定已知攻击路径的风险。它们都不完整,有些还有明显代价。上线前请先测试。

最后核实 2026-10-22

不存在能完全修复的配置

两份 PHP 官方公告都明确这样说。用它们争取几小时或几天,而不是几周。修复指南 →

各项措施的作用

措施效果CVE代价 / 副作用

memory_limit = -1(在管理员层面设置)+ cgroup 内存上限

首选
公告中最主要的配置缓解措施。去掉 PHP 自身的 OOM 中断,而大多数攻击路径都依赖它。两者改由操作系统杀掉失控的 worker,会中断请求。没有 cgroup 上限的话,单个请求就可能耗尽整台主机的内存。

session.upload_progress.enabled = 0

部分有效
可挡住已证实的会话路径,“但挡不住其他变种”(php.net)。必须在 php.ini、FPM 池或服务器配置里设置——不能用 .user.ini 或 ini_set()。…619依赖它的上传进度条会失效(很少见)。如果用不到,打补丁后也建议保持关闭。

fatal_error_backtraces = 0(PHP 8.5)

部分有效
只挡住已证实的致命错误回溯路径——这是 CVE-2026-109619 演示中最直接的情形。…619致命错误将不再包含回溯信息。

调低 post_max_size + 前端请求体大小限制

部分有效
减少攻击者在 multipart 解析阶段(应用运行之前)能制造的内存压力。php.net 建议:不需要上传文件时设 8M,需要时设 32M。…618也会限制上传——请测试正常的上传流程。

限制输入:max_input_nesting_level、max_input_vars、max_file_uploads、max_multipart_body_parts

部分有效
限制解析器带来的其他内存增长。…618大型或深层嵌套的表单可能会提交失败。

消除攻击者可触发的致命错误,以及按请求生效的无效 / 已弃用配置

部分有效
去掉 CVE-2026-109619 残留状态的来源:初始化前输出的诊断信息,以及回调、上传、导入和清理中的致命错误与超时。…619需要投入代码和配置审查工作。

调低 pm.max_requests(FPM)

部分有效
更频繁地回收 worker,让被破坏的状态存活更少的请求。公告提到的极端值是 1。…619有实际的 CPU 和延迟代价;对单请求攻击无效。

display_errors = 0

限制影响
防止错误输出向访客泄露细节。注意:隐藏诊断信息并不能阻止 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)。

可直接复制的配置

php.ini 附加配置
; /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
php-fpm 池
; /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 / nginx
# 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;
cgroup 内存上限
# 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 可以向扫描器隐藏版本号。这属于安全卫生,不是修复。