PHP的eval()函数能够将传入的字符串作为PHP代码执行,这一特性在动态配置、模板解析等场景中能带来便利,但如果处理不当,外部可控的变量被注入到eval()的执行内容中,就会引发任意命令执行风险,严重威胁应用安全。

eval()的风险来源
eval()的风险核心在于执行的内容是否可控。如果开发者直接将用户输入、接口返回的外部数据未经处理就拼接到eval()的参数中,攻击者就可以构造恶意字符串,注入任意PHP代码甚至系统命令,比如通过注入system('rm -rf /')这类代码,直接对服务器造成破坏。
常见的风险场景包括:直接使用$_GET、$_POST等全局变量拼接eval()参数,从不可信的配置文件、数据库中读取内容直接传入eval(),以及未对动态生成的代码做合法性校验就执行。
核心安全实践方案
1. 严格校验输入内容
如果必须使用eval()处理外部输入,首先要对输入内容做严格的白名单校验,只允许符合预期格式的内容通过。比如只允许输入数字、特定格式的字符串,禁止出现函数调用、系统命令相关的字符。
以下是一个简单的输入校验示例,只允许输入纯数字的表达式:
<?php
// 只允许输入数字和加减乘除运算符的表达式
$input = $_GET['calc'] ?? '';
if (preg_match('/^[0-9+-*/.]+$/', $input)) {
// 校验通过再执行,避免注入恶意代码
eval('$result = ' . $input . ';');
echo $result;
} else {
echo '输入内容不合法';
}
?>
2. 隔离执行环境
尽量避免在全局环境中使用eval(),可以将eval()的执行逻辑封装在独立的函数或类中,限制其内部可访问的变量和函数,避免攻击者利用全局变量进行进一步攻击。同时,不要将敏感变量(如数据库配置、密钥)传入eval()的执行上下文。
3. 禁用危险函数和类
在php.ini配置中,可以通过disable_functions参数禁用eval()可能调用的危险函数,比如system、exec、passthru、shell_exec等,即使eval()被注入恶意代码,也无法调用这些函数执行系统命令。
配置示例:
disable_functions = system,exec,passthru,shell_exec,proc_open,popen
4. 替代方案优先
绝大多数场景下,eval()都不是唯一的选择,优先使用更安全的替代方案。比如动态调用函数可以使用call_user_func(),解析配置可以使用json_decode()或parse_ini_file(),模板渲染可以使用成熟的模板引擎,从根源上避免eval()带来的风险。
风险排查与监控
定期对代码进行安全审计,搜索所有使用eval()的位置,检查是否存在外部变量直接传入的情况。同时可以开启PHP的日志记录,监控eval()的执行情况,如果发现异常的执行内容,及时排查处理。
最后需要明确,eval()本身属于高风险函数,除非没有更好的替代方案,否则不建议在业务代码中使用。如果必须使用,一定要严格落实上述安全实践,将风险降到最低。