Bashスクリプトでユーザー入力をサニタイズして、別のシェルプログラムに引数として渡すにはどうすればよいですか?次のことを防ぎたい:
INPUT="filename;rm -rf /"
ls $INPUT
次のように、ユーザー入力を二重引用符で囲むだけで十分だと思っていました。
ls "$INPUT"
しかし、$INPUT
に二重引用符がある場合はどうなりますか?
それとも、bashはすでにこの問題に対処していますか?
Bashはすでにそれを扱っています。引用するだけで十分です。
ls "$INPUT"
シェルがこの行を解析する方法の大まかなガイドは次のとおりです。
"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
変数はWord分割されません。 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
に渡します。意図していなかったファイルを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
「manbash」からの抜粋:
見積り
引用は、特定の文字または単語の特別な意味をシェルから削除するために使用されます。引用を使用して、特殊文字の特殊処理を無効にし、予約語がそのように認識されないようにし、パラメーターの拡張を防ぐことができます。
拡張
展開は、単語に分割された後、コマンドラインで実行されます。実行される展開には、ブレース展開、チルダ展開、パラメーターと変数の展開、コマンド置換、算術展開、ワード分割、パス名展開の7種類があります。
展開の単語数を変更できるのは、中括弧の展開、単語の分割、およびパス名の展開のみです。他の拡張は、単一の単語を単一の単語に拡張します。これに対する唯一の例外は、上記で説明した
"$@"
および"${name[@]}"
の拡張です(パラメーターを参照)。単語分割
シェルは、Word分割の二重引用符内で発生しなかったパラメーター展開、コマンド置換、および算術展開の結果をスキャンします。
見積もりの削除
上記の展開の後、上記の展開のいずれかから生じなかった、引用符で囲まれていない文字
\
、'
、および"
の出現はすべて削除されます。