ディレクトリ・トラバーサル
- Web サイトのパス名に上位ディレクトリ(../)を示す記号を入れることで、公開予定のないファイルを指定する方法
- 対策
- パス名を直接指定させない
- アクセス権を必要最低限にする
影響
- ウェブサーバ内のファイルの閲覧、改ざん、削除
- 本来公開していないファイルを閲覧されることで、重要情報の漏えいにつながる
- ウェブコンテンツ改ざんによるデマ、誹謗中傷の書き込みや、スクリプトファイルや設定ファイル削除によるサーバ機能停止などの被害を受ける可能性がある
検査方法
- ファイル名の入力欄に親ディレクトリを示す「../」を含む値を入力して送信し、本来参照できてはいけないファイルが表示されてしまった場合、そのシステムにはディレクトリ・トラバーサルの脆弱性が存在
対策
- 外部からファイル名を指定できる仕様を避ける
- ファイル名にディレクトリ名が含まれないようにする
- また、保険的対策としてファイル名の文字種の仕様を英数字に限定すれば、ディレクトリ・トラバーサル攻撃に用いる記号文字が使用できなくなるため、ディレクトリ・トラバーサルの対策になる
- PHP では basename() を使用することで、ディレクトリ名が含まれていてもファイル名だけを取得することが可能
- また、保険的対策としてファイル名の文字種の仕様を英数字に限定すれば、ディレクトリ・トラバーサル攻撃に用いる記号文字が使用できなくなるため、ディレクトリ・トラバーサルの対策になる
脆弱性コードの発見と修正方法
脆弱性のコード
<?php define('TMPLDIR', '/var/www/dt/tmpl/'); if (isset($_GET['template'])) { // 脆弱なコード readfile(TMPLDIR . $_GET['template']); } ?>
- $_GET['template'] に入力値があるときに readfile() で読み込む処理
- このようにディレクトリ階層(「../」)を含むファイル名を指定していると、ディレクトリ・トラバーサルの脆弱性になる
- $_GET['template'] に入力値があるときに readfile() で読み込む処理
修正コード
<?php define('TMPLDIR', '/var/www/dt/tmpl/'); if(isset($_GET['template'])){ // 修正したコード $file_name = basename($_GET['template']); readfile(TMPLDIR . $file_name); } ?>
- $_GET['template'] に格納されているファイル名からディレクトリ階層を basename() が除外して、readfile() に渡しています