在 Perl 中编码时安全地执行系统命令
Posted
技术标签:
【中文标题】在 Perl 中编码时安全地执行系统命令【英文标题】:Executing system commands safely while coding in Perl 【发布时间】:2012-10-23 04:30:24 【问题描述】:在 Perl 中编码时真的应该使用外部命令吗?我看到了它的几个缺点。它不是独立于系统的,还可能存在安全风险。你怎么看?如果没有办法,您必须使用 Perl 中的 shell 命令,那么执行该特定命令的最安全方法是什么(例如检查 pid、uid 等)?
【问题讨论】:
【参考方案1】:这取决于在 Perl 中复制该功能的难度。如果我需要在某些东西上运行m4
宏处理器,我不会考虑自己尝试在 Perl 中复制该功能,并且由于http://search.cpan.org/ 上没有看起来合适的模块,看来其他人会同意我的观点。在这种情况下,使用外部程序是明智的。另一方面,如果我需要读取目录的内容,那么在 Perl 中组合 readdir()
等加上 stat()
或 lstat()
比使用 ls
的输出更明智。
如果您需要执行命令,请仔细考虑如何调用它们。特别是,您可能希望避免 shell 解释参数,因此请使用 system
的数组形式(另请参阅 exec
)等,而不是命令加参数的单个字符串(这意味着使用了 shell处理命令行)。
【讨论】:
【参考方案2】:执行外部命令可能很昂贵,因为它涉及派生新进程并在需要时监视其输出。
可能更重要的是,如果外部进程因任何原因失败,您的脚本可能难以理解发生了什么。更糟糕的是,令人惊讶的是,外部进程经常会永远卡住,您的脚本也会如此。您可以使用特殊技巧,例如打开管道并在循环中观察输出,但这本身很容易出错。
Perl 非常有能力做很多事情。所以,如果你坚持只使用 Perl 原生结构和模块来完成你的任务,它不仅会更快,因为你从不分叉,而且通过查看原生 Perl 对象和由库例程。当然,它会自动移植到不同的平台。
如果您的脚本在提升的权限下运行(如 root 或在 sudo 下),您应该非常小心您执行的外部程序。确保基本安全性的简单方法之一是始终按全名指定命令,例如 /usr/bin/grep (但仍要三思而后行,只需通过 Perl 本身执行 grep!)。但是,如果攻击者使用 LD_PRELOAD 机制注入恶意共享库,即使这样可能还不够。
如果您愿意非常安全,建议使用 -T 标志来使用污染检查,如下所示:
#!/usr/bin/perl -T
如果您的脚本被确定为具有不同的真实有效用户或组 ID,Perl 也会自动启用污点标志。
污染模式将严重限制您在不抱怨 Perl 的情况下执行许多操作(如 system() 调用)的能力 - 请参阅 http://perldoc.perl.org/perlsec.html#Taint-mode 了解更多信息,但它会给您更高的安全信心。
【讨论】:
是的,污染模式会更加严格和安全。【参考方案3】:在 Perl 中编码时真的应该使用外部命令吗?
这个问题没有单一的答案。这完全取决于您在 Perl 的广泛潜在用途中所做的工作。
您是在本地机器上使用 Perl 作为一个美化的 shell 脚本,还是只是想找到一个快速而肮脏的解决方案来解决您的问题?在这种情况下,如果这是完成任务的最简单方法,那么运行系统命令就很有意义。安全性和速度不是那么重要;重要的是快速编码的能力。
另一方面,您正在编写生产程序吗?在这种情况下,您需要安全、可移植、高效的代码。通常最好在 Perl 中编写功能(或使用模块),而不是调用外部程序。至少,你应该认真考虑一下优点和缺点。
【讨论】:
以上是关于在 Perl 中编码时安全地执行系统命令的主要内容,如果未能解决你的问题,请参考以下文章