【问题标题】:Securely using the PHP exec function安全地使用 PHP exec 函数
【发布时间】:2012-01-20 02:49:48
【问题描述】:

我正在编写一个 PHP 脚本,旨在通过 exec() 函数运行可执行文件 (ffmpeg.exe)。问题是我已经读过使用 exec() 函数可能存在安全风险,应尽可能避免。我一直在研究如何安全地运行 exec() 函数,而我唯一遇到的就是使用 escapeshellcmd 或 escapeshellarg 过滤命令字符串。我想知道的是,在使用 exec() 函数时是否可以进一步提高安全性,或者是否有 exec() 的安全替代方案。任何帮助将不胜感激。

这是我的代码;

define('FFMPEG_LIBRARY', 'c:\\ffmpeg7\\ffmpeg\\bin\\ffmpeg ');
$transcode_string = FFMPEG_LIBRARY." -i " . $srcFile . " -acodec libmp3lame -ab 64k -ar 22050 -ac 1 -vcodec libx264 -b:v 250k -r 30 -f flv -y " . $destFile;
$transcode_string = escapeshellcmd($transcode_string);
exec($transcode_string);

$srcFile 基本上是用于转码的视频,而 $destFile 是我希望创建的输出文件。

【问题讨论】:

  • $srcFile 来自哪里,这个脚本将以什么身份使用?
  • 很抱歉。我已经编辑了我的问题以包含我正在使用的代码。
  • $srcFile$destFile 来自哪里?它们是否包含用户提供的值?
  • @Pekka:$srcFile 是上传的视频(例如 video.3gp),而 $destFile 是转码后的输出文件(例如 video.flv)。
  • @siberian 用户提供了文件名还是只提供了文件?

标签: php ffmpeg


【解决方案1】:

使用 exec() 函数可能存在安全风险,应尽可能避免。

这有点笼统 - 完全可以使用 exec() 构建安全解决方案。但这确实很难:执行外部程序有很多陷阱,尤其是当您向它们传递外部参数时。

如您所说,第一步是使用escapeshellarg() 转义所有内容,以防止注入其他可能有害的命令。

那么问题是输入错误的值会在被调用的程序中造成什么损害。例如,

  • 在 200000 x 200000 像素的大视频上运行 ffmpeg 操作很可能会导致服务器挂起,因为调用试图分配不可能的内存量。因此,您必须清理用户可以输入的尺寸值,如果它们太大或不是数字则退出。

  • 恶意用户可能会告诉 ffmpeg 使用配置文件并尝试从中创建视频,可能导致配置文件用作输出,因此您需要限制用户可以使用的文件路径范围指定。

等等等等。

另外,您需要考虑通过请求数量杀死服务器的可能性。如果我每秒向 PHP 脚本发送 50 个请求,该脚本又调用复杂的 ffmpeg 命令会怎样?服务器可能很容易在负担下崩溃,您可能希望防止这种情况发生。

所以:使用exec() 没有固有的安全问题,但是需要非常仔细地查看传递给它的每个传入参数。

【讨论】:

  • 避免有这么多挂断的事情如果可能似乎是一个合理的做法。 “永远不要使用它”完全是另一回事。
  • @preinheimer 是的,没错,我会为此添加一行。但是那些声称自己是安全专家并说“永远不要使用它”的人不知道他们在说什么。 (当然,如果是这样的话。)
  • @Pekka:他们并没有这么说。这只是我对他们所说的话的解释。我不记得我被告知的确切内容,只是在使用 exec() 或相关函数时我应该非常小心。对此感到抱歉。
  • @siberian 很公平——这肯定是个好建议。然后我会删除我的坏话:)
  • @Pekka:没关系。在将这部分添加到问题之前,我应该多考虑一下。
【解决方案2】:

exec 本身不是问题,问题是在将其放入 exec() 时绝对不应该接受用户输入。您应该始终使用 escapeshellarg(),但如果您确实需要接受用户输入,则在所有情况下都应该首先进行自己的清理和操作。

您的代码到底是什么?没有看到这件事没有更多可说的。

更新

如果 $srcFile 是上传文件的名称,那么您应该更改它。@preinheimer 的评论包含一个好主意,您可以调用 uniqid();并将 $srcFile 重命名为,然后您知道您有一个字母数字文件名,无论他们上传什么。将 $srcFile 更改为新的 uniqid()'d 文件名,您就可以开始了。

关于 $dstFile,将其设置为其他独特的,您可以调用 uniqid();再次,或使用当前时间。

如果你同时做这两件事,那么你根本就不会接受用户输入,你的脚本将是完全安全的。

【讨论】:

  • 我之前在一个已失效的启动中处理过类似的事情。我基本上从我的exec() 电话中删除了所有类似的用户输入。我使用uniqid() 作为文件名。选项不是直接从最终用户传入的,他们选择了带有整数的复选框,然后我将其转换为我使用的参数。
猜你喜欢
  • 2010-11-03
  • 1970-01-01
  • 2020-04-28
  • 2012-03-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-16
  • 2012-02-12
相关资源
最近更新 更多