如何显示命令并避免代码注入

如何显示命令并避免代码注入

我正在玩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"

在这种情况下,所有非字母数字都将被删除,并且代码将不会造成伤害

相关内容