网站漏洞防护的核心手段之一,就是在PHP运行环境中禁用"eval"函数并配置危险函数黑名单。"eval"函数能将字符串当作PHP代码执行,一旦被攻击者利用上传的恶意脚本调用,服务器就等于把执行权限完全交给了对方。具体做法是打开php.ini配置文件,找到"disable_functions"指令,将"eval"以及"system"、"exec"、"shell_exec"、"passthru"、"popen"、"proc_open"、"putenv"、"dl"等高危函数全部列入禁用列表。这不是可选项,而是任何生产环境PHP服务器的必做项。

很多站长觉得自己网站用的是成熟CMS就不需要管这些,实际上恰恰相反。WordPress、ThinkPHP、DedeCMS等主流系统的历史漏洞中,大量远程代码执行(RCE)攻击链都依赖"eval"或类似动态执行函数来完成提权。禁用这些函数不会影响正常业务逻辑,但能直接切断攻击者最常用的后门植入通道。

一、为什么必须禁用PHP eval函数

"eval"是PHP中最危险的函数,没有之一。它的作用是把一个字符串当作PHP代码来解析和执行。正常开发中几乎不需要用到它,但攻击者一旦找到文件上传漏洞或者模板注入点,就会构造类似这样的payload:

eval($_POST['cmd']);

只要这一行代码被写入到可访问的PHP文件中,攻击者就能通过POST请求执行任意系统命令。更隐蔽的写法是利用编码绕过,比如base64编码后再eval解码执行,或者用"assert"函数(本质也是eval)来绕过简单的关键词过滤。所以单纯靠WAF规则拦截关键词是不够的,必须从PHP运行层面彻底禁用。

从安全合规角度看,等保2.0三级以上要求对服务器进行安全加固,禁用危险函数是明确的检查项。PCI DSS标准同样要求最小化PHP可用函数集。不做这一步,等保测评直接不通过。

二、PHP危险函数完整黑名单及分类

危险函数不只是"eval"一个,需要系统性地梳理。按照危害程度可以分为以下几类:

第一类:代码执行类

这类函数能直接执行系统命令或PHP代码,危害最高:

eval, assert, system, exec, shell_exec, passthru, popen, proc_open, pcntl_exec

第二类:文件操作类

攻击者利用这些函数读取敏感文件、写入后门、修改配置:

file_get_contents, file_put_contents, fwrite, fread, fopen, unlink, rename, copy, move_uploaded_file, chmod, chown, touch, mkdir, rmdir, symlink, link, dl

第三类:信息泄露类

这些函数会暴露服务器内部信息,帮助攻击者进一步渗透:

phpinfo, get_current_user, getmyuid, getmypid, getenv, ini_get, ini_set, error_reporting, highlight_file, show_source, print_r, var_dump, debug_backtrace, debug_print_backtrace

第四类:网络与进程类

允许对外发起连接或操控进程:

fsockopen, curl_exec, curl_multi_exec, stream_socket_client, stream_socket_server, socket_create, socket_bind, socket_listen, socket_accept, putenv, pcntl_fork, pcntl_alarm

需要注意的是,并不是所有这些函数都要一刀切禁用。比如"file_get_contents"和"fopen"在正常业务中大量使用,禁用会导致网站无法运行。正确的做法是根据业务需求分级禁用,只禁用那些业务绝对用不到的高危函数。

三、具体配置方法:php.ini修改步骤

修改"disable_functions"是最直接有效的方式。操作步骤如下:

第一步,找到php.ini文件位置。不同环境路径不同:

Linux系统通常在:/etc/php/8.1/fpm/php.ini 或 /etc/php.ini
宝塔面板:/www/server/php/81/etc/php.ini
Windows系统:C:\php\php.ini

第二步,打开文件搜索"disable_functions",如果没有就手动添加一行:

disable_functions = eval,system,exec,shell_exec,passthru,popen,proc_open,putenv,dl,assert,pcntl_exec,pcntl_fork

第三步,保存文件后重启PHP服务使配置生效:

systemctl restart php-fpm
# 或者
service php8.1-fpm restart

第四步,验证是否生效。创建一个test.php文件:

<?php
phpinfo();
?>

在页面中搜索"disable_functions",确认目标函数已被禁用。也可以用命令行验证:

php -i | grep disable_functions
四、宝塔面板和虚拟主机环境的特殊处理

如果你用的是宝塔面板,可以在面板后台直接操作:进入"软件商店"→"PHP设置"→选择对应版本→"禁用函数",在文本框中填入函数名,用逗号分隔即可。宝塔会自动写入对应的php.ini文件。

对于虚拟主机用户,如果没有权限修改php.ini,可以在网站根目录创建一个"user.ini"文件(部分PHP版本支持),或者在".htaccess"中添加:

php_value disable_functions "eval,system,exec,shell_exec"

但需要注意,".htaccess"方式只在PHP以Apache模块模式运行时有效,如果是PHP-FPM模式则不生效。虚拟主机用户最稳妥的方式是联系主机商,要求在服务器层面配置。

五、仅禁用函数还不够:纵深防御策略

禁用危险函数只是第一层防护,真正的安全需要多层叠加。以下是必须同步做的事情:

1. 关闭PHP错误显示

生产环境必须关闭错误回显,否则攻击者可以通过报错信息获取路径和数据库信息:

display_errors = Off
log_errors = On
error_log = /var/log/php/error.log
error_reporting = E_ALL

2. 限制文件上传类型和目录

即使禁用了eval,如果攻击者能上传PHP文件到Web目录,仍然可以通过其他方式执行。所以要:限制上传扩展名为白名单、上传目录禁止执行PHP、重命名上传文件、使用随机文件名。

3. 使用open_basedir限制文件访问范围

在php.ini中配置:

open_basedir = /www/wwwroot/your_site/:/tmp/

这样PHP脚本只能访问指定目录内的文件,无法读取/etc/passwd等系统文件。

4. 部署Web应用防火墙(WAF)

WAF可以在HTTP层拦截恶意请求,配合PHP层面的函数禁用形成双重防护。常见的开源方案有ModSecurity、宝塔自带防火墙、云盾等。

5. 定期更新PHP版本和依赖组件

PHP 5.x早已停止安全维护,PHP 7.4也已EOL。务必使用PHP 8.1或8.2以上版本,新版本本身就移除或弱化了部分危险函数,安全基线更高。

六、禁用函数后常见兼容性问题及解决方案

禁用某些函数后,部分程序可能报错。常见情况和处理方式:

问题一:WordPress后台提示某些功能不可用

WordPress的某些插件会用到"exec"或"system"来执行定时任务。解决方案是使用WP-Cron替代系统cron,或者单独为该站点开放特定函数(通过不同的php.ini或FastCGI配置)。

问题二:图片处理库报错

GD库和ImageMagick的某些操作需要"exec"调用外部命令。可以改用纯PHP实现的图片处理方案,或者在隔离环境中单独允许。

问题三:Composer安装依赖失败

Composer本身不依赖这些危险函数,但某些post-install脚本可能会调用。检查composer.json中的scripts段,移除不必要的系统调用。

核心原则是:业务需要的函数保留,不需要的一律禁用。不要因为怕麻烦就全部放开,那等于没做防护。

七、自动化检测与持续监控

配置完成后,建议建立定期检查机制。可以写一个简单的监控脚本,每周检测一次disable_functions配置是否被篡改:

<?php
$ini = php_ini_loaded_file();
$content = file_get_contents($ini);
if (strpos($content, 'eval') !== false) {
    // 发送告警邮件
    mail('admin@yoursite.com', '安全告警', 'php.ini中eval未被禁用');
}
?>

同时结合文件完整性监控工具(如AIDE、OSSEC),检测Web目录下是否出现了可疑的PHP文件。任何非预期的新增PHP文件都应该触发告警。

八、总结与行动建议

PHP危险函数禁用是网站安全加固中投入产出比最高的操作之一。它不需要花钱、不需要复杂技术、不影响正常业务,却能直接封堵最常见的攻击路径。具体行动清单:立即检查当前php.ini中的disable_functions配置,补全缺失的高危函数;确认open_basedir和错误显示已正确设置;评估业务兼容性并做针对性调整;建立定期巡检机制。安全不是一次性工作,而是持续运营的过程。把基础防护做扎实,才能在面对真正的攻击时有底气。