Ruby 使用 open3 防止命令注入

Ruby prevent command injection with open3

在我正在处理的项目之一中,我们对 运行 系统命令使用了 backtip 方法。

resp = `7z x #{zip_file_path} -p#{password} -o#{output_path}`

效果很好。但由于它可能导致命令注入漏洞,我们计划使用 execopen3open3 我们在执行系统命令时遇到问题。我们参考 this 来解决命令注入问题。

stdin, stdout, stderr = Open3.popen3("7z", "x", zip_file_path, "-p", password, "-o", output_path)

但这会导致以下错误

error = stderr.readlines
# ["\n", "\n", "Command Line Error:\n", "Too short switch:\n", "-o\n"]

当我包含这样的参数时,这会起作用。

stdin, stdout, stderr = Open3.popen3("7z", "x", zip_file_path, "-p#{password}", "-o#{output_path}")

但是我们不应该单独传递参数来避免命令注入吗?或者我第一个版本有什么问题吗?

您的第二个版本(有效的那个):

stdin, stdout, stderr = Open3.popen3("7z", "x", zip_file_path, "-p#{password}", "-o#{output_path}")

绝对安全。没有涉及 shell,所以除了 7z 本身,没有任何东西可以解释 passwordoutput_path


不幸的是 7z 有一种奇怪的解析开关的方式。通常,您希望通过说 -p xyz 来将参数传递给开关,而 -pxyz 将是 -p -x -y -z 的缩写形式。当你说:

Open3.popen3("7z", "x", zip_file_path, "-p", password, "-o", output_path)

这就像在 shell 中这样说:

7z x zip_file_path -p password -o output_path

但是7z不喜欢那些空间,它想要:

7z x zip_file_path -ppassword -ooutput_path

所以您无法进行一些字符串插值。即便如此,Open3 没有涉及 shell,所以没有注入。