必须在php.ini和php-fpm pool中双重配置disable_functions,严格遵循全小写、无空格、无换行、无末尾逗号的语法,禁用exec、system、proc_open等函数,并分别验证cli与web环境生效。

禁用危险函数不是“可选项”,而是上线前必须完成的硬性动作——exec、system、proc_open 等函数一旦可用,攻击者只需一个未过滤的文件上传点或模板变量,就能写入 Webshell 并完全接管服务器。
怎么改 php.ini 才真正禁掉 exec 和同类函数
改错位置、格式有空格、没重启服务,等于没改。关键在三处:路径、语法、生效验证。
- 先确认 Web SAPI 实际加载的配置文件:
php --ini(CLI)或<?php echo php_ini_loaded_file(); ?>(Web),别只改/etc/php/8.4/cli/php.ini却漏了/etc/php/8.4/fpm/php.ini -
disable_functions值必须全小写、逗号后**零空格**:disable_functions = exec,system,shell_exec,passthru,proc_open,popen,pcntl_exec,assert,file_put_contents,symlink - 改完必须
systemctl restart php84-fpm(FPM)或systemctl restart apache2(Apache),reload不重读该配置 - 验证不能只看
phpinfo(),要实测:/www/server/php/84/bin/php -r "var_dump(system('id'));"应输出NULL并报PHP Warning: system() has been disabled
为什么 Nginx + PHP-FPM 下光改 php.ini 还不够
FPM pool 配置的 php_admin_value[disable_functions] 优先级高于 php.ini,很多宝塔或 Docker 环境默认就靠它生效,不手动覆盖就会被绕过。
- 打开对应 pool 文件(如
/etc/php/8.4/fpm/pool.d/www.conf),添加:php_admin_value[disable_functions] = exec,system,shell_exec,passthru - 确保该行未被注释,且没有拼写错误或尾部多余逗号
- 若站点需保留个别函数(如某监控工具要用
proc_open),不要动全局配置,而是在该站点的 PHP 配置片段中单独设置disable_functions,只禁其余函数 - 同步检查
security.limit_extensions = .php,否则攻击者传shell.php5可绕过解析限制
禁用函数后为什么页面空白或功能异常
很多老代码不检查返回值,exec() 被禁后直接返回 NULL,后续逻辑崩掉,但错误日志里只有 E_WARNING,前端却静默失败。
- 禁用后务必走真实业务流测试:上传文件、CMS 更新插件、后台导出报表等,不能只测单个函数调用
-
file_put_contents、copy、symlink等函数禁用后,可能影响 Composer 自动加载、日志轮转或临时文件生成,需结合open_basedir评估是否保留 - 如果发现某功能确实依赖被禁函数(如备份脚本调
system('tar -cf')),应重构为纯 PHP 实现,而非妥协放开函数 - 错误显示必须关:
display_errors = Off,否则E_WARNING会暴露路径和函数名,给探测提供线索
最常被忽略的一点是:禁用函数只是第一层,open_basedir 没设、上传目录允许执行 PHP、Nginx 的 fastcgi_param SCRIPT_FILENAME $request_filename 写法不安全——前面所有配置都白做。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











