PHP的disable_functions配置需确保真实生效、写法正确、禁用全面,并配合open_basedir、security.limit_extensions等措施堵住绕过路径。

PHP 的 disable_functions 配置本身不是漏洞,但配置不当(如没生效、写错、被绕过、禁得不全)会让它形同虚设,反而制造“已加固”的假象。修复核心是:**确保它真禁了、禁得对、禁得全,并配合其他限制手段堵住常见绕过路径。**
确认真实生效的配置文件位置
很多人改了错的 php.ini,重启后毫无效果。关键不是“有没有改”,而是“改的是不是 PHP 实际加载的那个”:
- Web 环境下,新建
info.php,内容为<?php phpinfo(); ?>,访问后搜索 Loaded Configuration File,记下那个绝对路径——这才是你要编辑的文件 - CLI 环境下,运行
php --ini,看 Loaded Configuration File 行(不是 Configuration File (php.ini) Path) - FPM 用户特别注意:
/etc/php/*/fpm/pool.d/www.conf中的php_admin_value[disable_functions]优先级高于 php.ini,必须一并检查 - 宝塔、Docker、cPanel 等环境常有多个配置层,漏掉一个就失效
修正 disable_functions 的写法错误
这个配置项极其脆弱,错一个字符就静默失效(PHP 不报错、不警告):
- 函数名必须全小写:
exec✅,EXEC❌,Exec❌ - 逗号是唯一分隔符,前后**绝对不能有空格**:
exec,system✅,exec, system❌(system变成带前导空格的字符串,匹配失败) - 禁止换行、禁止末尾逗号:
exec,system,❌(整行解析失败,值变为空) - 别只删
exec就完事——攻击者可用proc_open、pcntl_exec、shell_exec(含反引号)绕过,推荐禁用完整列表:exec,passthru,shell_exec,system,proc_open,popen,pcntl_exec,pcntl_fork,pcntl_waitpid,eval,assert,dl,ini_set,putenv,file_put_contents,symlink,link
验证是否真正禁用成功
不能只看 phpinfo() 页面里显示的值,必须实测调用:
立即学习“PHP免费学习笔记(深入)”;
- Web 端:写个测试脚本
<?php var_dump(exec('whoami', $out, $code)); print_r($out); echo "code: $code"; ?>,返回false且$code === -1或为空,才算禁成功 - CLI 端:运行
php -r "var_dump(exec('id'));",同样看返回值和退出码 - 注意:用
function_exists('exec')检查没意义——它返回 false 只说明函数不可见,不代表调用被拦截;必须实际执行
补上常见绕过缺口
光靠 disable_functions 不够,攻击者可能通过其他方式达成命令执行或文件操作:
-
限制文件操作范围:设置
open_basedir = /var/www/html:/tmp,防止读写敏感路径(如/etc/passwd) -
防止动态代码执行:禁用
eval和assert是基础,同时避免上传点写入恶意 PHP 文件后被include加载 -
关闭危险扩展:确认
extension=dl.so未启用(PHP 8+ 已移除dl(),但旧版本仍需检查) -
Nginx/FPM 安全配置:设置
security.limit_extensions = .php,防.phtml、.php5绕过;启用opcache.restrict_api = "/dev/null"(PHP 7.4+)防信息泄露



















