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

ES_*_*___ 9 shell shell-script

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

cd var; echo > create_a_file_here
Run Code Online (Sandbox Code Playgroud)

VAR是包含(希望)目录的地方,我想创建文件“create_a_file_here”的地方的字符串变量。现在,如果有人看到这行代码,就可以通过赋值来利用它,例如:

var = "; rm -rf /"
Run Code Online (Sandbox Code Playgroud)

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

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

ilk*_*chu 12

简单的解决方案:不要从您的程序中调用 shell。在所有。

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

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

如果您需要使用 shell,请引用命令行参数,或将它们传递到环境中,如Stéphane 的回答。此外,如果您发现自己担心特殊字符,正确的解决方案是不要尝试过滤掉(黑名单)有潜在危险的字符,而只保留已知安全的字符(白名单)。

只允许您知道其功能的角色,这样遗漏某些东西的风险就会降低。最终结果可能是您只决定允许[a-zA-Z0-9_],但这可能足以完成工作。您可能还想检查您的语言环境和工具集是否不包含像äö那样的重音字母。任何 shell 可能都不认为它们是特殊的,但同样,最好确定它们是否通过。


tel*_*coM 10

在编程语言中,应该有比执行 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") );
Run Code Online (Sandbox Code Playgroud)

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


Sté*_*las 9

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

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

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

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

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

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

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

  • 必须引用 shell 变量扩展以防止 split+glob
  • 你需要-Pcd做一个简单的chdir()
  • 您需要--标记选项的结尾以避免var开始-(或+在某些 shell 中)出现问题
  • 我们设置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 && ....");
Run Code Online (Sandbox Code Playgroud)

¹请注意,只是做了system(concat("cd \"", var, "\"; echo..."));不是要走的路,你只是移动的问题。

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

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

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