我正在玩wget
,我基本上做了一个脚本来下载一个页面,grep 该页面上的一些信息,然后wget
根据这些信息显示另一个页面。所以基本上,我的代码看起来像
defautltCommand="wget -v"
formValue=$(cat myfileA.html | get_field_value )
command="${defaultCommand} --post-data=\"myfield=${formValue}\""
echo "Command 3: ${command}"
echo "${command}" | bash
然而,这个解决方案有几个问题,主要的一个是如果 html 文件有一些邪恶的值(比如" google.com; <evil command>; ls "
),那么它就可以进行代码注入。因为我的脚本应该作为 NetworkManager 脚本以 root 身份运行...我想确保不可能注入代码。不过,我喜欢编写将要使用的命令的想法,这对于发生错误时的调试非常有用。
你有一个好的方法来确保我无法获得任何代码注入吗?或者也许您还有更好的方法?我的第一个想法是替换所有引用,如下所示:... | sed 's/"/\\/g"'
,但我不确定我是否捕获了注入代码的所有可能方法。
谢谢你!
答案1
将代码通过管道传输到 shell 中几乎总是错误的。在这里,您已经在 shell 中运行代码,绝对没有理由运行另一个 shell。
此外,不要通过将命令的各个部分放入字符串来构建命令。命令是一个字符串列表;如果你尝试将其填充到字符串中,你就会失去分隔参数的空格和参数内的空格之间的区别,和 当您尝试拆分字符串来运行它时,您会遇到其他问题,其中一些有安全影响。但无论如何你在这里都不需要它。你把事情搞得太复杂了。
form_value=$(cat myfileA.html | get_field_value )
wget -v --post-data="$form_value"
如果您希望该wget -v
部分可变,但是在你的脚本的控制下,并且您知道这些部分不会包含任何空格或任何\[*?
,那么您可以将该部分放入变量中。
wget='wget'
if [ -n "$verbose" ]; then
wget="$wget -v"
fi
form_value=$(cat myfileA.html | get_field_value )
$wget --post-data="$form_value"
如果您的脚本在 ksh 或 bash 或 zsh 下运行,但如果在普通 sh 下运行则不然,您可以将该命令放入数组中。
#!/bin/ksh
…
download=(wget -v --post-data="$form_value")
…
"${download[@]}"
当回显内容时,谨防控制字符,它们可能会导致您的终端执行操作或可能歪曲实际打印的内容。
echo "$wget --post-data=$form_value" | tr -c '[:print:]' '?'
答案2
如果要记录命令,可以使用标准xtrace
机制:
log_cmd() {
local - # assuming ash-based shells or bash-4.4+
# see set -o localoptions in zsh or use
# function log_cmd { syntax in AT&T ksh
# or replace {...;} with (...) POSIXly (but
# spawns a subshell)
typeset PS4="$1"; shift
set -o xtrace
"$@"
}
# here assuming a shell with arrays like ksh93, zsh, bash, yash
defautltCommand=(wget -v)
formValue=$(<myfileA.html get_field_value)
command=("${defaultCommand[@]}" "--post-data=myfield=$formValue")
log_cmd 'Command 3: ' "${command[@]}"
这样,您就永远不会对任意数据调用 shell 的解释器。
答案3
如果您的参数看起来像“A5h4f121SDEfdsZPfkshf457dsFJqsd”,您可以使用 sed 删除所有非字母数字。
像这样的东西:
#!/bin/bash
# sample function just not to think how to process your form
get_field_value () {
echo "ls -la; ps -ef;\"find . -iname test.txt\"; \`date +%Y%m%d\`"
}
# out of the bad command will be:
get_field_value
# >> ls -la; ps -ef;"find . -iname test.txt"; `date +%Y%m%d`
# your script begins here
#sample url
url="www.google.com"
# suggesting you have your file near your script
formValue=$(cat myfileA.html | get_field_value )
# remove all non-alphanumerics using sed
# formValue=$(echo "$formValue" | sed -e "s/[^a-zA-Z0-9]//g")
formValue=$(echo "$formValue" | sed -e "s/[^[:alnum:]]//g")
echo "Command 3: wget -v --post-data=\"$formValue\""
# >> Command 3: wget -v --post-data="lslapseffindinametesttxtdateYmd"
# run your command
wget -v --post-data="myfield=${formValue}" "$url"
在这种情况下,所有非字母数字都将被删除,并且代码将不会造成伤害