我们正在编写一个接收参数的Linux bash shell脚本。当脚本接收到可能的shell注入命令作为参数时,我们希望使脚本失败。我在下面使用正则表达式添加了一些命令。有人可以给我所有这些命令的列表,以便我们避免威胁
invalid_format="(^.*[;&|].*$)|(\brmdir\b)|(\bls\b)|(rm\s-)|(\bping\b)"
if [[ $LOCAL_DIR =~ $invalid_format ]]; then
echo "Error! LOCAL_DIR cannot contain command chaining characters like ; && || or possible shell injection commands"
exit 1
答案 0 :(得分:3)
数据中明确禁止的内容黑名单只是邀请某人提出其上未存在的漏洞,或混淆其代码以使正则表达式无法与之匹配或查找您的 actual 外壳程序认可的一种奇怪的语法,但黑名单/验证程序所使用的外壳程序则不支持。
不要打那失败的战斗;相反,通过编写绝对安全的代码无论您的数据包含什么内容,都不要在可能被评估和执行为代码的上下文中注入数据。
这本质上是不安全的:
eval "grep -e \"$1\" /var/log/*" ## DO NOT EVER DO THIS
eval "grep -e '$1' /var/log/*" ## DO NOT EVER DO THIS EITHER
sh -c "grep -e \"$1\" /var/log/*" ## DO NOT EVER DO THIS EITHER
sh -c "grep -e '$1' /var/log/*" ## DO NOT EVER DO THIS EITHER
ssh somehost "grep -e \"$1\" /var/log/*" ## DO NOT EVER DO THIS EITHER
ssh somehost "grep -e '$1' /var/log/*" ## DO NOT EVER DO THIS EITHER
在所有这些情况下,用户提供的值($1
)用于将由Shell解析为代码的上下文中。在所有这些情况下,值都可以运行任意命令。
这始终是安全的:
grep -e "$1" /var/log/* ## ALWAYS DO THIS INSTEAD
同样,这始终是安全的。即使$(rm -rf ~)\'$(rm -rf ~\)'
中有$1
之类的内容,shell也不会将任何内容作为语法进行评估,因此这些值本质上无法解析为代码。
system()
或同等的这本质上是不安全的:
system("grep -e \"" + input + "\" /var/log/*") /* DO NOT EVER DO THIS */
system("grep -e '" + input + "' /var/log/*") /* DO NOT EVER DO THIS EITHER */
这本质上是安全的:
setenv("logs_to_grep", input); /* IF YOU MUST USE system(), DO THIS INSTEAD */
system("grep -e \"$logs_to_grep\" /var/log/*")
请注意,我们如何根本不将值放在传递给shell的字符串中,而是在环境变量中使用带外传递(使用小写名称,因此无法覆盖)对操作系统和支持工具具有安全敏感性的任何环境变量。
假设您需要通过SSH输入不受信任的输入来运行命令。 printf %q
可以帮助:
printf -v args_q '%q ' "$@"
ssh somehost 'bash -s' <<EOF
command_with $args_q
EOF
为什么使用bash -s
?为确保您的args_str
被bash解析,因为printf %q
不保证POSIX安全输出。
使用直接使用system()
系统调用来调用脚本的语言级工具,而不是使用sh -c
或调用execve()
的任何东西。例如,在Python中:
# BAD/EVIL/INSECURE
subprocess.Popen('yourscript ' + arg, shell=True) ## DO NOT EVER DO THIS
# GOOD/SECURE
subprocess.Popen(['yourscript', arg]) ## DO THIS INSTEAD.
xargs -I{} sh -c 'something_with {}'
-因为您的占位符{}
替换为sh
解析为代码的值,因此将其解析为代码,而不是数据。不要那样做。
相反,请带外传递数据:xargs -d $'\n' sh -c 'for arg; do something_with "$arg"; done' _
(如果您的数据本来就不能包含换行符,则不能使用;如果无法证明是真的,请使用NUL分隔符和{{1} })。
xargs -0
-与上述find . -type f -exec sh -c 'something_with {}' \;
相同的问题,并且具有相同的解决方案:xargs
请勿使用find . -exec sh -c 'for arg; do something_with "$arg"; done' _ {} +
或eval
或将非恒定字符串解析为代码的任何其他内容。同样,这些值在您的数据内都非常好且安全;您根本不应该在代码中使用它们 。
除了操作系统强制执行的文件名外,不要假设文件名。请勿在脚本中使用source
。不要用换行符分隔文件名-而是使用NUL。