最有效方式是直接在php.ini中配置disable_functions,需确保小写、无空格、单行逗号分隔,并配合FPM pool的php_admin_value强制锁定,改后必须重启服务并分Web/CLI环境验证生效。

直接在 php.ini 里用 disable_functions 指令禁用,是最有效、最通用的方式。它不依赖 Web 服务器类型(Apache/Nginx/IIS/Caddy/FrankenPHP),也不分 PHP 运行模式(CLI/FPM/模块),只要配置正确并重启服务,就能真正切断高危函数调用链。
一、精准填写 disable_functions 列表
打开你实际生效的 php.ini 文件(别改错位置),找到或新增这一行:
disable_functions = exec,passthru,shell_exec,system,proc_open,popen,pcntl_exec,eval,assert,create_function,call_user_func,call_user_func_array,symlink,link,chmod,chown,chgrp,putenv,ini_set,curl_exec,file_get_contents注意这些细节:
- 全部小写,大小写敏感(
EXEC或Eval不生效) - 逗号后不能有空格(
exec, system❌ 只禁了exec) - 行末不能多一个逗号(
exec,❌ 整行失效) - 不能换行写,PHP 不支持跨行解析
- 业务若真用到某个函数(如旧系统依赖
ini_set),可临时剔除,但需评估替代方案
二、FPM 环境必须额外加 pool 配置
仅改 php.ini 不够——PHP-FPM 下,应用层可能用 ini_set() 或扩展绕过。必须在 FPM pool 配置中强制锁定:
立即学习“PHP免费学习笔记(深入)”;
编辑 /etc/php/*/fpm/pool.d/www.conf(或对应 pool 文件),在 [www] 段内添加:
然后执行:sudo systemctl reload php*-fpm(不是 restart,避免中断)
三、验证是否真生效
改完不验证 = 白改。两个环境都要测:
-
Web 环境:建
test.php,内容为<?php echo exec('id'); ?>,访问应返回空白页,并在错误日志里看到Warning: exec() has been disabled -
CLI 环境:终端运行
php -r "echo exec('id');",同样应报 warning - 再查一次生效路径:
php -r "echo php_ini_loaded_file();"和php -r "echo ini_get('disable_functions');",确认值与你写的完全一致
四、配套加固不能少
关函数只是第一步,攻击者会绕着走:
-
关错误显示:设
display_errors = Off,开log_errors = On并指定安全日志路径 -
锁文件访问范围:设
open_basedir = /var/www/html:/tmp(按实际根目录调整) -
禁远程加载:设
allow_url_fopen = Off和allow_url_include = Off -
隐藏版本信息:设
expose_php = Off -
上传目录禁止执行:Nginx/Apache 配置中明确禁止
.php在/uploads等目录下运行



















