使用字符串变量保护 shell 命令

使用字符串变量保护 shell 命令

在编程语言中,我执行一个简单的 shell 命令

cd var; echo > create_a_file_here

变量是一个变量,其中包含一串(希望)目录到我想要创建文件“create_a_file_here”的位置。现在,如果有人看到这行代码,就可以通过分配来利用它,例如:

var = "; rm -rf /"

事情可能会变得非常难看。避免上述情况的一种方法可能是搜索字符串变量对于一些特殊字符,例如“;”在执行 shell 命令之前,但我怀疑这涵盖了所有可能的漏洞。

有谁知道一个好方法来确保“cd var”只更改目录而不更改其他内容?

答案1

简单的解决方案:不要从程序中调用 shell。完全没有。

这里的示例很简单,无论使用哪种编程语言,更改目录和创建文件都应该很容易。但即使您确实需要运行外部命令,通常也不需要通过 shell 来执行。

因此,例如在 Python 中,不要运行 ,而是os.system("somecmd " + somearg)使用subprocess.run(["somecmd", somearg]).在 C 中,system()使用fork()and exec()(或找到一个可以执行此操作的库)来代替。

如果您需要使用 shell,请引用命令行参数,或通过环境传递它们,如下所示史蒂芬的回答。另外,如果您发现自己担心特殊字符,正确的解决方案是不是尝试过滤掉(黑名单)潜在危险字符,但仅限保持已知安全的字符(白名单)。

只允许使用您确实知道其功能的字符,这样就可以减少遗漏某些内容的风险。最终结果可能是您只决定允许[a-zA-Z0-9_],但这可能足以完成工作。您可能还需要检查您的区域设置和工具集是否不包含像äö这样的重音字母。任何 shell 可能都不认为它们是特殊的,但再次强调,最好确定它们是否通过。

答案2

如果我理解正确的话,var它是你的编程语言中的一个变量。

在您的编程语言中,您要求 shell 解释一个字符串,该字符串是"cd "、该变量的内容和 的串联"; echo > create_a_file_here"

如果那么,是的,如果内容var没有严格控制,那就是命令注入漏洞。

您可以尝试在 shell 语法中正确引用变量 1 的内容,以便保证它作为单个参数传递给cd内置函数。

另一种方法是以另一种方式传递该变量的内容。一个明显的方法是将其传递到环境变量中。例如,在 C 中:

char *var =  "; rm -rf /";
setenv("DIR", var, 1);
system("CDPATH= cd -P -- \"$DIR\" && echo something > create_a_file_here");

这次,你要求 shell 解释的代码是固定的,我们仍然需要用 shell 的语法正确地编写它(这里假设是一个 POSIX 兼容的 shell):

  • shell 变量扩展必须加引号以防止 split+glob
  • 你需要-Pcd一个简单的chdir()
  • 您需要--标记选项的结尾以避免以(或在某些 shell 中)var开头出现问题-+
  • 我们设置CDPATH为空字符串,以防它在环境中
  • 我们仅在成功echo时运行该命令。cd

(至少)还存在一个问题:如果var-,它不会 chdir 进入被调用的目录-,而是进入以前的目录(如存储在$OLDPWD),并且OLDPWD=- CDPATH= cd -P -- "$DIR"不保证能够解决它。所以你需要类似的东西:

system(
  "case $DIR in\n"
  " (-) CDPATH= cd -P ./-;;\n"
  " (*) CDPATH= cd -P -- \"$DIR\";;\n"
  "esac && ....");

¹ 请注意,只需执行 asystem(concat("cd \"", var, "\"; echo..."));即可不是要走的路,你只是转移问题。

例如,avar = "$(rm -rf /)"仍然是一个问题。

仅有的为类似 Bourne 的 shell 引用文本的可靠方法是使用单引号还要注意字符串中可能出现的单引号。例如,将 achar *var = "ab'cd"转至char *escaped_var = "'ab'\\''cd'"。也就是说,将 all 替换''\''并将整个内容包裹在其中'...'

这仍然假设反引号内没有使用带引号的字符串,并且您仍然需要--, -P, &&, CDPATH=...

答案3

在编程语言中,应该有比执行 shell 命令更好的方法来完成任务。例如,替换cd var为您的编程语言的等效项chdir (var);应确保任何值为 的欺骗行为var只会导致“找不到目录”错误,而不是意外和可能的恶意操作。

此外,您可以使用绝对路径而不是更改目录。只需连接目录名、斜杠和您要使用的文件名即可。

在 C 语言中,我可能会这样做:

char filepath[PATH_MAX];  /* alternative constant: MAXPATHLEN */

/* Join directory name in var and the filename, guarding against exceeding PATH_MAX */
snprintf (filepath, PATH_MAX, "%s/%s", var, "create_a_file_here");

/* create an empty file/truncate an existing one */
fclose (fopen (filepath, "w") );

你的编程语言肯定可以做类似的事情吗?

相关内容