ディレクトリトラバーサル

ディレクトリトラバーサルは、「../」を使ってディレクトリの上の階層に移動できるため、ウェブサーバのトップページの外側にあるファイルにも接続することが可能です。そのため、UNIX系のオペレーティングシステムではpasswd fileなどの内容が漏洩します。

攻撃される場所

ディレクトリトラバーサルはリクエストをPHP fileに記述したポストやゲットなどの変数で受け取ることによって発生します。下記コードを記述したPHP fileを例えばドキュメントルートに設置した場合、「../」を使ってpasswdファイルまでの位置を指定したパスをフォームに入力することで、passwd fileの中身が出力されてしまいます。$_GETを使った変数では、URLの最後尾に「?attackFilePath=passwdファイルへのパス」という形式で送信することでpasswdファイルの中身が出力されてしまいます。尚、ポスト送信では「「?attackFilePath=」の部分は不要です。

// HTML
<form action="" method="post">
<input type="text" size="40" name="AttackFilePath" value="" />
<input type="submit" value="クリック" />
</form>
// PHP
$file='/ドキュメントルート/'.$_POST['AttackFilePath'];
readfile($file);

ディレクトリトラバーサルの対処法

ディレクトリトラバーサルをini_set()で制限する

構文は「ini_set('open_basedir', '/制限したいパス/');」です。
ドキュメントルートより上の階層へアクセスさせないためには、ドキュメントルートまでのパスを指定します。例えばApacheのルートディレクトリでは「/var/www/html/」といった感じになります。
ini_set()のopen_basedirはPHPからアクセスできるファイルを指定したディレクトリツリーに限定することができます。しかしPHP5.2.6とPHP5.3.4以降以外のバージョンでは、この制限をプレフィックスとして取り扱っており、例えば「/dir/inc」などとしてもアクセスができます。もしこれをディレクトリに限定する場合は、末尾にスラッシュを付けます。(プレフィックスはPHPの古いバージョンで採用されていたものであり、PHP7などではディレクトリ名で制限指定します。)

ディレクトリトラバーサルをホワイトリストで制限する

if(isset($_POST["AttackFilePath"]) === true && $_POST["AttackFilePath"] !==''){
if(!in_array($_POST["attackFilePath"], array(読込OKファイルパス1, 読込OKファイルパス2 [,・・・]))){
exit;
}
$file='/ドキュメントルート/'.$_POST['AttackFilePath'];
readfile($file);
}

上記コードは配列で指定されたファイル内に、$_POST["AttackFilePath"]が無い場合にexitで処理を終了しています。また、$_GETで記述している場合は、$_POSTを$_GETにします。

ディレクトリトラバーサルをその他の方法で対応

接続を許可するFileが多いケースでは、ブラックリストで制限します。しかし、基本的にディレクトリトラバーサルは、ホワイトリストで対応する方が確実です。また、不正文字を取り除くという方法もありますが、こちらは想定していないディレクトリへの接続を防ぐメリットがありますが、階層構造を扱うことが出来ません。そのため、臨機応変に処理対応を変更する方が合理的です。