防止php视频转码命令注入漏洞的核心做法是彻底放弃使用`exec()`、`system()`等函数直接拼接用户输入,转而调用封装好的安全库(如ffmpeg的php绑定)或使用白名单机制。具体而言,应将所有外部参数通过数组形式传递给`proc_open()`或`shell_exec()`,确保系统将其视为纯数据而非可执行指令;同时,对文件路径和输出文件名进行严格的正则校验,仅允许字母、数字、下划线及连字符,从而从根源上阻断恶意shell元字符的注入。

如何验证旧版代码中的注入风险
在旧版实现中,开发者常直接将`$_POST['filename']`拼接到FFmpeg命令字符串中,这会导致严重的命令注入。例如,若攻击者传入`test.mp4; rm -rf /`,系统会将分号后的内容作为独立命令执行。这种风险源于未对用户输入进行任何清洗就直接传递给底层Shell解释器,使得任意命令得以运行。

$filename = $_GET['file']; // 危险:直接拼接用户输入 $cmd = "ffmpeg -i $filename output.mp4"; system($cmd); // 若 filename 为 'test.mp4; cat /etc/passwd',则 passwd 被泄露
如何使用白名单与数组参数修复漏洞
修复该漏洞的标准做法是使用`escapeshellarg()`包裹所有可变参数,并严格限制输入格式。更安全的方案是使用`proc_open()`并传入参数数组,这样操作系统不会启动Shell解析器,从而避免了解析分号、管道符等元字符的风险。同时,应定义一个允许的文件扩展名白名单,拒绝非视频文件的处理请求。
立即学习“PHP免费学习笔记(深入)”;

$filename = $_GET['file'];
// 1. 白名单校验
if (!preg_match('/^[a-zA-Z0-9_-]+\.mp4$/', $filename)) {
die('Invalid file');
}
// 2. 使用 escapeshellarg 安全转义
$safeFilename = escapeshellarg($filename);
$cmd = "ffmpeg -i {$safeFilename} output.mp4";
// 3. 推荐使用 proc_open 配合数组参数(更安全)
// $process = proc_open('ffmpeg', [
// ['pipe', 'r'],
// ['pipe', 'w'],
// ['pipe', 'w']
// ], $pipes);
// proc_close($process);
// 此处简化演示 shell_exec 的安全用法
$output = shell_exec("ffmpeg -i {$safeFilename} output.mp4 2>&1");
echo $output;
基于程序输出结果的具体问题分析
当使用`escapeshellarg()`处理后,即使攻击者尝试注入`test.mp4; rm -rf /`,最终执行的命令也会变成`ffmpeg -i 'test.mp4; rm -rf /' output.mp4`。此时,Shell会将整个带引号的字符串视为唯一的输入文件名,由于该文件不存在,FFmpeg会返回“文件未找到”的错误,而不会执行后续的删除命令。这一结果证实了参数隔离的有效性,即恶意字符被当作普通文本处理,失去了命令执行的能力。



















