PHP中system()、exec()等函数被禁用是因为命令注入风险高,必须对每个参数独立白名单校验、禁止动态拼接、优先使用枚举和固定模板,并辅以basename()、escapeshellarg()等防护措施。

为什么system()、exec()这些函数不能直接用
PHP 8.1 没新增或删减命令执行函数,但运行时环境(尤其是生产服务器)普遍禁用 system、exec、shell_exec、passthru、proc_open 等函数——不是因为语法变了,而是因为它们天然具备高危能力:任意命令拼接 = 服务器沦陷。一旦用户可控输入(如 $_GET['filename'])未经校验就进到 exec("ls -l " . $_GET['filename']),攻击者传 filename=; rm -rf / 就能触发命令注入。
白名单校验必须在参数拼接前完成
白名单不是“把危险字符过滤掉”,而是“只允许极少数已知安全的值”。常见错误是先拼字符串再检查,比如:
// ❌ 错误:先拼再判,已执行了危险逻辑
$cmd = "convert -resize " . $_POST['size'] . " " . $_POST['input'];
if (preg_match('/^[a-zA-Z0-9_\-\.]+$/', $_POST['input'])) { ... }
正确做法是:对每个参与命令构造的变量,单独做白名单匹配,且仅在匹配成功后才进入命令组装流程。关键点:
- 每个参数独立校验,不共用正则或逻辑
- 白名单值必须是完整、确定的字符串(如
"thumb"、"large"),避免用正则匹配路径片段 - 禁止使用
escapeshellarg()作为兜底——它只能防注入,不能防业务逻辑越权(比如用户传../../etc/passwd还是能被读) - 优先用枚举或配置数组比对,而非正则。例如:
in_array($_POST['action'], ['resize', 'rotate', 'crop'], true)
实际命令封装建议用固定模板 + 参数插槽
不要动态拼接命令字符串。把可变部分严格限制为白名单校验后的变量,其余全部写死。例如图像处理场景:
PHP 8.5.12 RC 1 候选版修复 BZ2、DOM、PDO、Opcache/JIT 和扩展内存安全问题,改进 Unicode 字素处理、URL 解析、TLS 流状态、信号分发及会话错误处理。
立即学习“PHP免费学习笔记(深入)”;
// ✅ 正确:模板清晰,变量来源受控
$allowedSizes = ['small' => '120x120', 'medium' => '400x400', 'large' => '1200x800'];
$sizeKey = $_POST['size'] ?? '';
if (!isset($allowedSizes[$sizeKey])) {
die('Invalid size');
}
$cmd = sprintf('convert -resize %s %s %s',
escapeshellarg($allowedSizes[$sizeKey]),
escapeshellarg('/var/www/uploads/' . basename($_POST['file'])),
escapeshellarg('/var/www/output/' . uniqid() . '.jpg')
);
exec($cmd, $output, $returnCode);
注意这里三个要点:
-
basename()强制截取文件名,防止路径穿越 -
escapeshellarg()仅用于已通过白名单/格式校验的变量,不替代白名单 - 输出路径用
uniqid()生成,不拼接用户输入
PHP 8.1 特性可辅助提升校验可靠性
PHP 8.1 的 enum 和 readonly 不直接防命令注入,但能减少人为失误导致的绕过:
- 用
enum定义所有合法动作:enum ImageAction: string { case Resize = 'resize'; case Rotate = 'rotate'; },校验时直接ImageAction::tryFrom($_POST['action']) !== null - 用
readonly属性封装命令上下文,避免中间变量被意外覆盖:public readonly string $safeOutputPath; - 启用
strict_types=1防止字符串和数字隐式转换绕过in_array的strict检查
真正难的是把“哪些命令要跑”和“谁有权限跑”拆开设计。白名单只是第一道门,后面还得配权限系统、日志审计、沙箱环境——否则哪怕只放行一个 ping,也能被用来探测内网拓扑。


















