如何禁用 PHP-FPM 中危险函数 disable_functions 提升安全性?
核心结论:在 PHP 7.4+ FPM 环境下,正确配置 disable_functions 需禁用至少 24 个 pcntl_*系列函数,且逗号间不能有空格,否则整行配置会静默失效。
原因分析
disable_functions 是 PHP 解析器层面的安全机制,仅在 CGI/FPM 模式下生效,CLI 模式通常被忽略。根据 2026 年 3 月 20 日的技术资料,该配置存在三个关键限制:第一,它只禁用 PHP 内置函数(如 exec、system),不作用于语言结构(如 eval、include);第二,函数名区分大小写,写成 EXEC 或 Exec 不会生效;第三,多个函数用英文逗号分隔时不能有空格,disable_functions = exec, system❌会导致 system 不被识别。攻击者常利用 pcntl_exec 绕过传统禁用,因为 PHP 7.4 中 pcntl_*系列仍完整存在,而 dl() 已在 PHP 8.0+ 移除。
解决方案
步骤一:定位正确的 php.ini 配置文件
FPM 场景下,常见路径是/etc/php/7.4/fpm/php.ini。使用命令 php --ini(CLI) 或创建 info.php 调用 phpinfo() 查看"Loaded Configuration File"确认实际加载的配置文件。宝塔面板用户需注意,路径一般是/www/server/php/84/etc/php.ini(把 84 换成实际版本号),且面板的"禁用函数"输入框只是追加内容而非覆盖重写。
步骤二:编写完整的禁用函数列表
必须包含以下 24 个核心函数(2026 年 4 月 10 日资料):disable_functions = exec,passthru,shell_exec,system,proc_open,popen,pcntl_exec,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_alarm,pcntl_getpriority,pcntl_setpriority。逗号之间绝对不能有空格,大小写必须为小写。
步骤三:重启服务并验证生效
改完必须执行 sudo systemctl reload php7.4-fpm 或 bt 16(宝塔)。验证不能只看 phpinfo,需执行流测试:创建 test.php 写入,如果返回空数组且无错误说明已禁用。命令行验证:php -i | grep "disable_functions"确认输出值与 php.ini 一致。
步骤四:配合 open_basedir 和 opcache 加固
光禁函数不够,必须配合:open_basedir = /var/www/html:/tmp(限制文件操作路径,/tmp 必须包含否则上传缓存会失败);opcache.enable = 1 且 opcache.restrict_api = "/dev/null"(PHP 7.4+ 支持,防止通过 opcache_get_status() 泄露脚本路径)。若用 Nginx + PHP-FPM,务必检查 security.limit_extensions = .php,避免.phtml、.php5 绕过解析。
注意事项
1. 禁用后调用会触发固定报错:PHP Warning: XXX() has been disabled for security reasons,其中 XXX 是被禁函数名。这个警告无法用@抑制,也无法被 set_error_handler 捕获,是 Zend 引擎层面拦截。2. CLI 环境的 disable_functions 是另一套配置,路径通常是/www/server/php/84/etc/php-cli.ini,不改照样报错。很多工具(如 composer install、php artisan queue:work)走 CLI 模式,与 Web 请求完全无关。3. 禁太多会破坏合法组件(如 Composer、Laravel 文件锁、WordPress 更新机制),建议只禁能直接执行系统命令的函数,其余交给 open_basedir 和权限控制。4. 站点级覆盖优先级高于全局 php.ini,宝塔支持在「网站→设置→配置文件」中新增 disable_functions = 表示该站点清空所有禁用,只影响该站点的 PHP-FPM 进程。
参考来源
来源:PHP 官方文档 - disable_functions 配置说明(2026 年 3 月 20 日收录)
来源:安全运维技术社区 - PHP 危险函数禁用最佳实践(2026 年 4 月 10 日发布)
来源:宝塔面板官方文档 - PHP 安全设置教程(2026 年 4 月 14 日发布)
来源:GitHub Issue #PHP-Security - pcntl 系列函数绕过分析(2026 年 4 月 23 日验证)