对文件名进行评估,邪恶吗?

对文件名进行评估,邪恶吗?

我有以下用于创建项目的脚本:

clear
version="0.0.2"
echo "Project creator"
echo "---------------"
# ask user to specify a directory (could start with spelled-out home directory)
directoryName=""
# Input must meet the following criteria: 
# 1.) No spaces at all in the directory path
# 2.) some characters must be entered
while [[ ${#directoryName} -eq 0 || $directoryName == *" "* ]]
        do
                echo -e "\nEnter the full directory of the project (no spaces):"
                read directoryName
        done
echo "You entered: $directoryName"
# uate directoryName so that the rest of the code can understand it
# create directory if it does not exist
eval mkdir "$directoryName"
# if successful
if [ $? -eq 0 ]
then
        # call executable in /home/miwarren/CPPFileCreator to create a main.cpp file to put in the folder
        $HOME/CPPFileCreator/a.out $directoryName
        # copy a run.sh file into the folder, too...
        eval cp $HOME/CPPFileCreator/run.sh $directoryName/run.sh
        # you might want to put a fileCreator.sh in the folder as well
        eval cp $HOME/fileCreator.sh $directoryName/fileCreator.sh
fi

我确保删除所有空格(假设每个不安全字符串中至少有一个空格,因为注入式攻击)。我希望用户在存在变量时不必拼写路径部分(例如,$HOME主目录)。

我在这里还可以使用吗eval?如果不行,该怎么办?

答案1

“我希望用户在存在变量时不必拼写路径部分(例如,$HOME 表示主目录)。”

无需以下操作即可完成eval

$ s='$HOME/.config'
$ s="${s//\$HOME/$HOME}"
$ echo "$s"
/home/john1024/.config

这有一些限制。其一,如果 HOMES 和 HOME 都是要替换的变量名称,那么为了避免错误匹配,必须替换 HOMES家。

对所有导出的变量应用替换

使用bash:

while IFS== read -r name val
do
   s="${s//\$$name/$val}"
done < <(printenv)

例如:

$ export A=alpha; export B=beta
$ s='$HOME/$A/$B'
$ while IFS== read -r name val; do s="${s//\$$name/$val}"; done < <(printenv)
$ echo "$s"
/home/john1024/alpha/beta

由于这种方法不按长度对变量名进行排序,因此存在上面提到的变量重叠问题。

我们可以通过根据长度对变量名进行排序来解决这个问题:

while IFS== read -r n name val
do
   s="${s//\$$name/$val}"
done < <(printenv | awk '/^[^ \t]/{key=$0; sub(/=.*/,"",key); printf "%s=%s\n",length(key),$0}' | sort -rnt=)

如果用户输入一个变量名不是存在但初始字符与某个较短的名称匹配,则较短的名称将被替换。如果这很重要,我们可以通过要求用户使用以下代码对此变量使用大括号表示法来避免它:

while IFS== read -r n name val
do
   s="${s//\$\{$name\}/$val}"
done < <(printenv | awk '/^[^ \t]/{key=$0; sub(/=.*/,"",key); printf "%s=%s\n",length(key),$0}' | sort -rnt=)

举个例子:

$ s='${HOME}/${A}/${B}'
$ while IFS== read -r n name val; do s="${s//\$\{$name\}/$val}"; done < <(printenv | awk '/^[^ \t]/{key=$0; sub(/=.*/,"",key); printf "%s=%s\n",length(key),$0}' | sort -rnt=)
$ echo "$s"
/home/john1024/alpha/beta

答案2

在这里使用eval没有任何意义。在决定如何修复脚本之前,仔细考虑您的要求并将其写下来。阅读您的问题,很明显您对自己想要做什么没有清楚的了解,并且在弄清楚您对解决方案的期望之前,您不会解决这个问题。

假设每个不安全字符串中至少有一个空格

不,甚至还差得远。您的脚本允许用户执行任意代码,因为它允许用户键入不包含空格和换行符的任何字符串。用户可以使用制表符和分号来代替。即使没有任何空格,用户也可以键入命令替换:

`touch /tmp/this_is_executed`somefile
$(touch /tmp/this_is_executed)somefile

这是一个问题吗?这取决于您想要做什么。输入是否来自从普通帐户运行脚本的用户?如果是这样,则不存在安全问题,但脚本从标准输入读取输入是没有意义的:它应该采用命令行参数,然后命令行 shell 会执行您想要的变量扩展。如果您的脚本以提升的权限运行或通过网络获取输入,那么eval绝对是邪恶的,并且在您了解其含义之前不应使用它。eval接受一个字符串作为参数(如果它有多个参数,它们之间用空格连接在一起)并将其作为 shell 代码执行。如果您不想执行 shell 代码,则eval该工具是错误的。

如果脚本采用非特权输入,那么它就是执行变量扩展的错误位置。在向脚本提供输入的界面中执行此操作,以用户的权限运行(例如,如果输入来自 Web 浏览器,则使用 Javascript)。在脚本中,您需要检查指定的文件名是否位于用户应该有权访问的目录中。小心..可能允许转义目录树的符号链接,以及关于-可以解析为选项而不是文件名的前导

相关内容