我想从一个C程序中调用一个带有文件名参数的shell脚本。用户可以控制文件名。C代码如下(初始化/错误检查已省略):
sprintf(buf, "/bin/sh script.sh \"%s\"", filename);
system(buf);
目标设备实际上是一个嵌入式系统,因此我不需要担心恶意用户。显然,在Web环境中,这将成为攻击向量。但是,如果系统上有一个文件名,例如包含反引号的名称,则命令将失败,因为shell将对名称执行扩展。有没有办法防止命令替换?
我想从一个C程序中调用一个带有文件名参数的shell脚本。用户可以控制文件名。C代码如下(初始化/错误检查已省略):
sprintf(buf, "/bin/sh script.sh \"%s\"", filename);
system(buf);
目标设备实际上是一个嵌入式系统,因此我不需要担心恶意用户。显然,在Web环境中,这将成为攻击向量。但是,如果系统上有一个文件名,例如包含反引号的名称,则命令将失败,因为shell将对名称执行扩展。有没有办法防止命令替换?
嗯,你可以使用fork()和execv()函数重新实现system()。
http://www.opengroup.org/onlinepubs/000095399/functions/system.html
由于您标记为 C,我将为您提供 C 的答案。 您需要转义文件名 - 创建一个新字符串,该字符串将由 shell 正确处理,使得像 This is a file name
产生 This\ is\ a\ file\ name
或者 bad;rm *;filename
变成 bad\;rm\ \*\;filename
。然后您可以将其传递给 shell。
绕过这个问题的另一种方法是使用 fork
和其中一个 exec
函数直接运行 shell。 直接将参数传递给程序不会导致 shell 命令行扩展或解释。
system
,而是应该自己使用fork
和execv
。但是为了回答如何使字符串安全地传递给shell的问题(如果您坚持使用system
),您需要转义字符串。最简单的方法是首先将每个'
(单引号)替换为'\''
(单引号,反斜杠,单引号,单引号),然后在字符串开头和结尾添加'
(单引号)。另一种相当简单(但通常不太有效)的方法是在每个字符前面放置一个反斜杠,但是然后您仍然需要做一些特殊的引号技巧来处理嵌入式换行符,因此我更喜欢第一种方法。
'
代替双引号"
。Bash 不会进行替换。例如:sprintf(buf, "/bin/sh script.sh '%s'", filename);
。然后一切都取决于script.sh
在做什么。您可能还想为受限 shell 指定-r
,但在这种 shell 中有一些限制,有关更多详细信息,请参阅 bash 手册页中的“受限 shell”部分。 - user405725