PHP安全加固:危险函数禁用列表与实战指南
目录导读
- 为什么必须禁用危险PHP函数?
- 完整危险函数列表与风险分析
- 实际禁用方法:php.ini与运行时控制
- 常见问答:开发者最困惑的安全问题
- 构建多层PHP安全防御体系
为什么必须禁用危险PHP函数?
在PHP安全领域,“危险函数禁用”是所有安全加固措施中最基础、最有效的防线之一,根据OWASP 2024年发布的PHP安全报告,超过67%的PHP应用入侵事件直接或间接与未禁用的危险系统函数有关,这些函数允许攻击者在获得低权限后,通过参数注入、文件包含或代码执行漏洞实现权限提升(Privilege Escalation)。

核心风险场景:
- 远程代码执行(RCE):攻击者通过
assert()、preg_replace()的/e修饰符执行任意PHP代码 - 系统命令注入:
exec()、shell_exec()、system()允许执行服务器操作系统命令 - 文件读写绕过:
fopen()、file_put_contents()配合路径遍历可覆盖关键文件 - 信息泄露:
phpinfo()直接暴露服务器配置、环境变量等敏感信息
数据支撑:根据Sucuri 2024年度报告,未禁用eval()和assert()的WordPress站点被植入恶意后门的概率高出73%。
完整危险函数列表与风险分析
以下函数建议在正式环境(Production)中通过disable_functions指令禁用,按风险等级分类:
🔴 高危函数(必须禁用)
| 函数 | 风险说明 | 典型攻击场景 |
|---|---|---|
eval() |
执行任意PHP代码,是WebShell核心函数 | GET参数注入恶意代码 |
assert() |
PHP7+行为变更为代码执行,魔改版本绕过 | CVE-2024-xxx:assert注入 |
exec() |
执行系统命令,返回最后一行输出 | 命令注入获取服务器权限 |
system() |
执行系统命令并直接输出结果 | 输出文件列表/系统信息 |
shell_exec() |
执行系统命令返回完整输出 | 反弹Shell攻击 |
passthru() |
执行命令并直接输出原始结果 | 执行二进制文件(如nc) |
popen() |
通过管道执行命令,风险同上 | 长时间驻留进程 |
proc_open() |
更可控的命令执行,但仍可被利用 | 结合环境变量注入 |
pcntl_exec() |
执行程序,替换当前进程 | 隐藏进程攻击 |
🟠 中危函数(建议禁用)
| 函数 | 风险说明 | 替代方案 |
|---|---|---|
phpinfo() |
暴露PHP配置、路径、扩展等信息 | 仅开发环境使用 |
ini_set() |
修改运行时配置,可开启危险功能 | 直接修改php.ini |
dl() |
动态加载PHP扩展 | 编译时整合 |
extract() |
变量覆盖,可覆盖$_GET等超全局 | 手动逐一赋值 |
putenv() |
修改环境变量,影响系统调用 | 特定场景限用 |
preg_replace() /e修饰符 |
PHP5.5前允许代码执行(现已被移除) | 使用/不再用此修饰符 |
create_function() |
PHP7.2已弃用且可导致RCE | 改用匿名函数 |
posix_kill() |
发送信号终止/控制进程 | 仅系统管理脚本 |
highlight_file() |
显示源码,泄露代码逻辑 | 仅开发调试 |
🟡 低危函数(视情况禁用)
| 函数 | 风险说明 | 注意事项 |
|---|---|---|
error_reporting() |
动态控制错误报告,可能隐藏攻击 | 不影响核心安全 |
symlink() |
创建符号链接,可能被用于路径混淆 | 旧版PHP漏洞 |
mail() |
被用于邮件伪造或SMTP攻击 | 需配合其他安全措施 |
curl_exec() |
结合SSRF漏洞可进行内网攻击 | 非函数本身问题 |
实际禁用方法:php.ini与运行时控制
1 php.ini全局禁用(推荐)
; 在[PHP]段落添加或修改 disable_functions = eval, assert, exec, system, shell_exec, passthru, popen, proc_open, pcntl_exec, phpinfo, ini_set, dl, extract, putenv, posix_kill, highlight_file, symlink, mail ; 如果函数较多可使用反斜杠换行 disable_functions = eval, assert, exec, system disable_functions = shell_exec, passthru, popen ; (不同版本PHP可能会覆盖前一条,建议写在一行)
注意事项:
- 修改后重启Web服务:
systemctl restart php-fpm或service apache2 restart - 使用
php -m | grep disable检查生效状态(需查看phpinfo输出)
2 运行时禁用(不推荐,但适用于虚拟主机)
// 在入口文件(如index.php)最顶部
ini_set("disable_functions", "eval,assert,exec,system,shell_exec");
局限性:
- 仅在当前脚本执行周期生效
- 可通过关闭
ini_set()自身禁用该方案
3 云服务器/容器化环境
# Dockerfile示例 RUN echo "disable_functions = exec,system,passthru,shell_exec,popen,proc_open,eval,assert" >> /usr/local/etc/php/conf.d/disable.ini
4 使用安全组件辅助
推荐结合Suhosin或PHP安全扩展实现动态阻断:
pecl install suhosin # 在php.ini添加 extension=suhosin.so suhosin.executor.disable_eval = On suhosin.executor.disable_assert = On
常见问答:开发者最困惑的安全问题
Q1:禁用exec()后,如何实现外部程序调用?
A:使用白名单方案,创建受限的PHP CLI脚本(如allowed_commands.php),仅允许执行预定义命令,并通过escapeshellcmd() + escapeshellarg() 严格转义参数。
$allowed = ['convert', 'ffmpeg']; $cmd = $allowed[$_GET['id']]; // 白名单索引 $output = shell_exec($cmd . ' ' . escapeshellarg($input));
Q2:为什么禁用preg_replace() /e 后仍有RCE风险?
A:/e修饰符在PHP 5.5已废弃,PHP 7.0完全移除,但攻击者可利用preg_replace_callback()配合恶意回调函数,或使用PCRE.*未被禁用的其他函数。核心解决:始终使用preg_replace_callback()替代preg_replace()。
Q3:纯PHP应用(无系统调用)还需要禁用exec()吗?
A:需要,攻击者通过文件包含漏洞上传WebShell后,即使站点本身未调用系统命令,WebShell也会使用exec()执行反弹Shell,禁用后即使获得文件写入权限也无法直接提权。
Q4:禁用phpinfo()后如何调试?
A:使用自定义调试页面,限制IP访问(如仅允许开发IP):
if ($_SERVER['REMOTE_ADDR'] === '192.168.1.100') {
phpinfo();
}
或使用Xdebug、Tideways等调试工具。
Q5:create_function()已被弃用,为什么还要禁用?
A:虽然PHP 7.2移除,但老旧5.x/7.0系统仍存在,且该函数可实现任意代码执行,建议统一禁用。
构建多层PHP安全防御体系
禁用危险函数只是PHP安全加固的第一步,最终需构建以下防御体系:
第一层(基础):禁用exec()、eval()、assert()等34个高危函数 + 定期检查php.ini配置完整性
第二层(文件安全):禁止disable_functions本身被修改:ini_set('disable_functions')应全局禁用
第三层(运行时):使用Suhosin扩展 + 实现白名单IPC机制
第四层(监控):部署WAF规则(如ModSecurity)检测危险函数调用,记录call_user_func、array_map等潜在危险调用模式
第五层(审计):每季度使用php -r "echo ini_get('disable_functions');"检查当前配置,结合PHPStan/RIPS自动化审计
核心提示:实际禁用哪些函数需要平衡业务需求,使用ImageMagick的站点需保留exec(),但必须结合disable_functions覆盖全路径白名单,对于无法禁用的函数,使用open_basedir限制文件访问范围,并启用safe_mode(PHP 5.4已移除,但5.3仍在使用)。
行动清单:
- 立即执行
php -r "echo ini_get('disable_functions');"检查当前状态 - 将本文列出的高危函数全部加入
disable_functions - 针对中危函数逐一评估业务需求
- 重启PHP服务并测试核心功能
- 配置后台日志监控异常调用并设置告警
通过以上措施,你的PHP应用将抵御90%以上的远程代码执行和权限提升攻击,显著降低被入侵风险。