注: Python 2.7.4 以降では、これは ZIP アーカイブの問題ではありません。回答の下部に詳細があります。この回答は、tar アーカイブに焦点を当てています。
パスが実際に指している場所を把握するには、を使用しますos.path.abspath()
(ただし、パス コンポーネントとしてのシンボリック リンクに関する警告に注意してください)。zipfile からのパスを正規化し、プレフィックスとして現在のディレクトリが含まれabspath
ていない場合は、その外側を指しています。
ただし、アーカイブから抽出されたシンボリック リンクの値も確認する必要があります (tarfile と unix zip ファイルの両方にシンボリック リンクを格納できます)。これは、システム ライブラリに自分自身をインストールするだけのアプリケーションではなく、意図的にセキュリティをバイパスすることわざのような「悪意のあるユーザー」を心配している場合に重要です。
これは前述の注意事項abspath
です。サンドボックスにディレクトリを指すシンボリックリンクが既に含まれている場合、誤解を招く可能性があります。サンドボックス内を指すシンボリック リンクでさえ危険な場合があります。シンボリック リンクはsandbox/subdir/foo -> ..
を指すsandbox
ため、パスsandbox/subdir/foo/../.bashrc
は許可されません。これを行う最も簡単な方法は、以前のファイルが抽出されるまで待ってから使用すること os.path.realpath()
です。幸いなことextractall()
にジェネレーターを受け入れるので、これは簡単に行うことができます。
コードを要求するので、アルゴリズムを説明するビットを次に示します。サンドボックス外の場所へのファイルの抽出 (要求されたもの) だけでなく、サンドボックス外の場所を指すサンドボックス内のリンクの作成も禁止します。誰かが迷子になったファイルやリンクをこっそり盗むことができるかどうか知りたい.
import tarfile
from os.path import abspath, realpath, dirname, join as joinpath
from sys import stderr
resolved = lambda x: realpath(abspath(x))
def badpath(path, base):
# joinpath will ignore base if path is absolute
return not resolved(joinpath(base,path)).startswith(base)
def badlink(info, base):
# Links are interpreted relative to the directory containing the link
tip = resolved(joinpath(base, dirname(info.name)))
return badpath(info.linkname, base=tip)
def safemembers(members):
base = resolved(".")
for finfo in members:
if badpath(finfo.name, base):
print >>stderr, finfo.name, "is blocked (illegal path)"
elif finfo.issym() and badlink(finfo,base):
print >>stderr, finfo.name, "is blocked: Hard link to", finfo.linkname
elif finfo.islnk() and badlink(finfo,base):
print >>stderr, finfo.name, "is blocked: Symlink to", finfo.linkname
else:
yield finfo
ar = tarfile.open("testtar.tar")
ar.extractall(path="./sandbox", members=safemembers(ar))
ar.close()
編集: Python 2.7.4 以降では、これは ZIP アーカイブの問題ではありません: メソッドzipfile.extract()
は、サンドボックス外でのファイルの作成を禁止します:
注:メンバー ファイル名が絶対パスの場合、ドライブ/UNC 共有ポイントと先頭の (バック) スラッシュは取り除かれます。たとえば、Unix では に///foo/bar
なり、Windows ではになります。また、メンバー ファイル名のすべてのコンポーネントが削除されます。たとえば、 になります。Windows では、不正な文字 ( 、、、、、および) [は] アンダースコア (_) に置き換えられます。foo/bar
C:\foo\bar
foo\bar
".."
../../foo../../ba..r
foo../ba..r
:
<
>
|
"
?
*
クラスはtarfile
同様にサニタイズされていないため、上記の回答は引き続き適用されます。