以下のスクリプトを前提として、引数に/home/charlesingalls/
内の有効なファイル名のみが含まれ、パス(../home/carolineingalls/
)やワイルドカードなどが含まれていないことをどのように確認できますか?
スクリプトが特定のハードコードされたディレクトリから単一のファイルを削除できるようにしたいだけです。このスクリプトは、特権ユーザーとして実行されます。
#!/bin/bash
rm -f /home/charlesingalls/"$1"
この回答は、$1
にサブディレクトリを含めることが許可されていることを前提としています。 $1
が単純なディレクトリ名である必要があるより単純なケースに興味がある場合は、他の回答の1つを参照してください。
二重引用符で囲んだ場合、ワイルドカードは展開されません。 $1
は二重引用符で囲まれているため、ワイルドカードは問題になりません。
../
とシンボリックリンクの両方が、ファイルの実際の場所を覆い隠す可能性があります。以下に示すのは、ファイルが実際に、見た目だけでなく、必要なパスの下にあるかどうかを判断するためのテストです。
realpath
の使用ファイルが本当に/home/charlesingalls/
の下にあるかどうかを確認するには、realpath
を使用できます。
realpath --relative-base=/home/charlesingalls/ "/home/charlesingalls/$1" | grep -q '^/' && exit 1
上記は、exit 1
で指定されたファイルがディレクトリ$1
の下以外の場所にある場合、/home/charlesingalls/
を実行します。 realpath
はパス全体を正規化し、シンボリックリンクと../
の両方を削除します。
realpath
はGNU coreutilsの一部であり、すべてのLinuxシステムで使用できるはずです。
realpath
には GNU coreutils 8.15(2012年1月)以上 が必要です。
Realpathが../
に従ってファイルの実際の場所を決定する方法を示すために(たとえば、grepの実際の出力が表示されるようにgrepの-q
オプションは省略されています):
$ touch /tmp/test
$ realpath --relative-base=$HOME "$HOME/../../tmp/test" | grep '^/' && echo FAIL
/tmp/test
FAIL
シンボリックリンクをたどる方法を示すには:
$ ln -s /tmp/test ~/test
$ realpath --relative-base=$HOME "$HOME/test" | grep '^/' && echo FAIL
/tmp/test
FAIL
readlink -e
を使用readlink
は、シンボリックリンクと../
の両方に従って、パスを非正規化することもできます。
readlink -e "$HOME/test" | grep -q "^$HOME" || exit 1
同じサンプルファイルの使用:
$ readlink -e "$HOME/../../tmp/test" | grep "$HOME" || echo FAIL
FAIL
$ readlink -e "$HOME/test" | grep "^$HOME" || echo FAIL
FAIL
古いGNUシステムで利用可能であることに加えて、readlink
のバージョンがBSDで利用可能です。
パスを完全に禁止する場合、最も簡単な方法は、変数にスラッシュ(/
)が含まれているかどうかをテストすることです。 bashで:
if [[ "$1" = */* ]] ; then...
ただし、これにより、foo/bar
を含むすべてのパスがブロックされます。代わりに..
をテストすることもできますが、その場合、シンボリックリンクがターゲットパス外のディレクトリを指す可能性があります。
1つのファイルの削除のみを許可したい場合は、rm -r
を使用するべきではないと思います。
また、実行している内容によっては、システムのファイル権限を使用して、ユーザーが自分で削除できるファイルの削除のみを許可することもできます。このようなもの:
su charlesingalls -c "rm /home/charlesingalls/'$1'"
@Gillesがコメントしたように、これには引用の問題があります:$1
に単一引用符が含まれていると失敗します。そのため、最初に変数をテストする必要があります(例:if [[ "$1" = *\'* ]] ; then fail...
、または賢明なセットをホワイトリストに登録することによって)文字の)、または環境変数を介して渡されるファイル名。
file="$1" su charlesingalls -c 'rm "/home/charlesingalls/$file"'