本文目录导读:

在PHP项目中使用 exec() 函数执行系统命令确实会带来严重的安全风险,以下是主要风险及详细说明:
命令注入攻击
风险描述
攻击者通过输入恶意内容修改或扩展要执行的命令。
示例
// 危险代码
$user_input = $_GET['domain'];
exec("ping " . $user_input, $output);
// 攻击者输入: example.com && cat /etc/passwd
// 实际执行: ping example.com && cat /etc/passwd
危害
- 执行任意系统命令
- 读取敏感文件
- 删除或修改数据
- 建立反向shell
参数注入
风险描述
即使使用参数化命令,攻击者仍可能通过参数注入特殊字符。
// 不安全的参数传递
exec("grep " . escapeshellarg($_GET['pattern']) . " /var/log/nginx/access.log", $output);
// 某些PHP版本或配置下仍可能存在风险
路径遍历
风险描述
攻击者通过特殊路径访问系统文件。
exec("cat " . $_GET['file'], $output);
// 输入: ../../etc/passwd
命令输出泄露
风险描述
命令执行结果直接返回给用户,可能暴露敏感信息。
exec("whoami", $output);
echo implode("\n", $output);
// 暴露系统用户信息
资源耗尽风险
风险描述
攻击者可能触发资源消耗型命令:
exec("dd if=/dev/zero of=/dev/null bs=1M count=1000", $output);
// 或者
exec(":(){ :|:& };:", $output); // Fork炸弹
权限提升风险
风险描述
Web服务器运行用户权限提升:
exec("sudo systemctl restart nginx", $output);
// 如果配置不当,可能导致权限提升
竞态条件
风险描述
并发执行导致的意外行为:
exec("rm -rf /tmp/" . session_id() . "/*", $output);
// 多个请求同时执行可能导致竞态条件
安全建议
避免使用exec(首选)
// 使用PHP内置函数替代 file_get_contents() // 替代cat, curl等 scandir(), glob() // 替代ls mkdir(), rmdir() // 替代mkdir, rmdir
严格输入验证
function safe_exec($cmd, $params) {
$allowed_commands = ['df', 'uptime', 'who'];
if (!in_array($cmd, $allowed_commands)) {
throw new Exception("Command not allowed");
}
$safe_params = array_map('escapeshellarg', $params);
$full_cmd = $cmd . ' ' . implode(' ', $safe_params);
exec($full_cmd, $output);
return $output;
}
白名单过滤
$allowed_domains = ['google.com', 'github.com'];
if (!in_array($domain, $allowed_domains)) {
die("Invalid domain");
}
最小权限原则
# 创建专门用于脚本执行的用户 sudo useradd -s /sbin/nologin webapp # 只授予必要权限
安全配置
ini_set('execisecure', '1'); // 禁用exec函数
// 或
disable_functions = exec,system,passthru
输出过滤
exec($cmd, $output);
$safe_output = array_map('htmlspecialchars', $output);
安全替代方案
如果需要执行系统命令,考虑:
- proc_open(): 更安全的进程管理
- shell_exec(): 限制输出
- 使用消息队列异步执行
- Web服务API替代直接命令执行
最重要的安全原则:永远不要信任用户输入,尽可能避免使用 exec() 函数,如果真的需要,要进行多层防护并严格限制权限。