disable_functions 是 php 解析器强制拦截开关,必须禁用三类函数(进程执行、动态代码、文件/网络操作),并在 fpm pool 层用 php_admin_value 锁定、重启服务后实测验证,同时关闭 allow_url_fopen、allow_url_include 等配套选项。

disable_functions 不是可选项,而是 PHP 解析器层面的强制拦截开关——漏掉任何一个仍具执行能力的函数,攻击者就能用它写 Webshell、读取 /etc/passwd、反弹 shell 或打穿内网。
PHP 8.5.5 本身没有新增高危函数,但攻击链从未停止进化:一个未禁用的 symlink 配合日志包含可造 shell;漏掉 curl_exec 就可能被用于 SSRF 扫描内网服务;assert 在 PHP 8.3+ 仍支持字符串参数动态执行,是 RCE 常见入口。只禁 exec 和 system 等显眼函数,等于留着后门钥匙在门把手上。
必须禁用的三类函数(PHP 8.5.5 实际有效清单)
不是照抄旧列表,而是按当前版本真实能力筛选:
-
exec、system、shell_exec、passthru、proc_open、popen—— 直接 spawn 进程,命令注入主通道 -
eval、assert、pcntl_exec—— 动态代码执行或进程替换,绕过静态分析 -
file_put_contents、copy、symlink、link、chown、chgrp、chmod、curl_exec—— 写文件、提权、内网探测,配合路径遍历或日志包含即可落地
为什么 php.ini 里设了还不算完?
disable_functions 在 php.ini 中可被运行时调用 ini_set() 或某些扩展绕过。生产环境必须在 FPM Pool 层用 php_admin_value[disable_functions] 强制锁定:
- 编辑
/etc/php/8.5/fpm/pool.d/www.conf(路径依实际版本调整) - 在
[www]段内添加:php_admin_value[disable_functions] = exec,system,shell_exec,passthru,proc_open,popen,eval,assert,file_put_contents,copy,symlink,link,chown,chgrp,chmod,curl_exec - 确认用的是
php_admin_value,不是php_flag—— 后者不支持字符串赋值 - 执行
systemctl restart php8.5-fpm,仅 reload 不生效
禁用后怎么验证真生效了?
别只看服务重启了没,要实测调用:
- CLI 验证:
/usr/bin/php -r "var_dump(function_exists('proc_open'));"应输出bool(false) - Web 验证:建个
test.php,内容为<?php echo system('id'); ?>,访问应返回空白页 + PHP 错误日志里出现Function system is disabled - 检查最终生效值:
php -i | grep disable_functions,输出必须是你填的完整列表,且无空格、无换行、无多余逗号 - 注意 Suhosin 等安全扩展可能覆盖配置,以
phpinfo()页面输出为准
容易被忽略的配套动作
单靠 disable_functions 是瘸腿防护:
-
allow_url_fopen和allow_url_include必须设为Off—— 否则include('http://...')可绕过所有函数禁用 -
open_basedir必须在 FPM Pool 里配,不能只写在 php.ini —— FPM 下 php.ini 的 open_basedir 无效 -
expose_php = Off要同步设,否则X-Powered-By: PHP/8.5.5直接暴露版本,方便攻击者查对应 CVE - 错误显示必须关:
display_errors = Off且log_errors = On,否则异常堆栈里脱敏参数仍会吐到前端
allow_url_include —— 任何一处松动,都可能让整套配置形同虚设。php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











