在bash中对用户输入进行清理以确保安全性

34

我该如何在bash脚本中对用户输入进行净化,以便我可以将其作为参数传递给另一个shell程序?我希望避免以下情况:

INPUT="filename;rm -rf /"
ls $INPUT

我认为只需要像这样用双引号将用户输入括起来即可:

ls "$INPUT"

但是如果$INPUT中有双引号怎么办?

或者说bash已经解决了这个问题吗?

1个回答

44

简述

Bash已经处理了这个问题,加上引号即可。

ls "$INPUT"

长话短说

关于shell如何解析这行命令的简单指南:

"ls \"$INPUT\""                     # Raw command line.
["ls", "\"$INPUT\""]                # Break into words.
["ls", "\"filename; rm -rf /\""]    # Perform variable expansion.
["ls", "\"filename; rm -rf /\""]    # Perform word splitting (no change).
["ls", "filename; rm -rf /"]        # Remove quotes.

由于引号的存在,$INPUT 变量不会被分割为多个单词。因此 ls 命令会寻找一个名为 filename; rm -rf / 的文件。

如果没有使用引号,展开过程将会有所不同:

"ls $INPUT"                             # Raw command line.
["ls", "$INPUT"]                        # Break into words.
["ls", "filename; rm -rf /"]            # Perform variable expansion.
["ls", "filename;", "rm", "-rf", "/"]   # Perform word splitting.
你至少可以安慰自己,这不会真正执行rm -rf /。相反,它将把每个字符串作为文件名传递给ls。你会列出一些意外的文件,但至少不会意外执行不想要的命令。
jkugelman$ VAR='.; echo hi'
jkugelman$ ls $VAR
ls: .;: No such file or directory
ls: echo: No such file or directory
ls: hi: No such file or directory

来自“man bash”的摘录:

引用

引用用于去除某些字符或单词在Shell中的特殊含义。引用可以用于禁用特殊字符的特殊处理,防止保留字被识别为这样的字符,以及防止参数扩展。

扩展

扩展是在命令行被分割成单词之后执行的。执行七种扩展:大括号扩展、波浪线扩展、参数和变量扩展、命令替换、算术扩展、单词分割和路径名扩展。

只有大括号扩展、单词分割和路径名扩展可以改变扩展的单词数;其他扩展会将一个单词扩展为一个单词。唯一的例外是上面解释的"$@""${name[@]}"的扩展(请参见PARAMETERS)。

单词分割

Shell将未在双引号内出现的参数扩展、命令替换和算术扩展结果进行单词分割。

引号删除

在进行上述扩展之后,将删除所有未引用出现的字符\'"


5
好的建议,但有一个例外,这不适用于 eval - SiegeX
请注意,在Bash 4.0之前,波浪号展开会执行globbing(但不会分割),除非使用临时变量(或使用set -f完全禁用globbing),否则无法避免这种情况。 - Stephane Chazelas
2
请注意,一般来说,如果您不打算列出目录的内容,则应执行ls -- "$INPUT"ls -d -- "$INPUT" - Stephane Chazelas
2
我知道这是一个旧帖子,但“eval”是一个重要的案例。如果他们执行了eval ls $INPUT,那么“rm”命令将被执行。如果涉及到eval,则反引号和$(cmd)子表达式也可能存在威胁。 - rich p

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接