← コラム一覧

ディレクトリトラバーサルとは|攻撃の仕組み・ログの見分け方・対策と午後対策

ディレクトリトラバーサル(パストラバーサル)の仕組みを、実際のアクセスログの読み方と併せて解説。「../ の除去」では防げない理由と、正規化・索引方式による根本対策、情報処理安全確保支援士の午後問題での問われ方まで。

ディレクトリトラバーサル(パストラバーサル、CWE-22)は、Web アプリが「どのファイルを返すか・読むか」を利用者から受け取った文字列で決めているときに、その文字列を無検査でファイルの場所(パス)の組み立てに使ってしまうことで成立する脆弱性です。攻撃者は、本来公開するつもりのないファイル——設定ファイル、データベースの接続情報、/etc/passwd、ソースコードなど——をアプリに読み出させ、外部へ持ち出します。実装言語やフレームワークを問わず、「利用者入力をパスに使う」設計であれば、どこでも起こり得ます。

攻撃の入口はどこか

典型的な入口は、ファイル名や文書 ID をパラメータで受け取る機能です。「?path=2026/annai.pdf」のように配布物を指定する download 機能、「?template=header.html」のようにテンプレートを読み込む機能、画像やレポートのダウンロード機能などが該当します。アプリはこの文字列を基準ディレクトリ(配布物の置き場所)に連結して開こうとします。

BASE_DIR = "/srv/docs"

# 受け取った文字列をそのまま連結している(危険)
target = os.path.join(BASE_DIR, param)
return send_file(target)

# param = "annai.pdf"                → /srv/docs/annai.pdf(正常)
# param = "../app/config.ini"        → /srv/app/config.ini(外に出た)
# param = "../../../../etc/passwd"   → /etc/passwd(もっと外へ)

os.path.join や文字列連結は「../」を特別扱いしません。連結した結果を OS がパスとして解決するとき、「..」は一つ上の階層へ移動するため、基準ディレクトリの外側にあるファイルを指せてしまいます。

利用者の指定(param) annai.pdf ../app/config.ini ../../../../etc/passwd 連結して解決されるパス /srv/docs/annai.pdf 基準の内側 /srv/app/config.ini 外へ出た /etc/passwd 外へ出た 基準ディレクトリ /srv/docs に連結しただけでは、「..」で外へ出られる。 正規化した結果が基準の内側かを検査してはじめて止まる。
図:利用者の指定が、そのまま基準ディレクトリの外を指してしまう

ログでの見分け方

インシデント対応では、まずアクセスログとアプリのログを突き合わせます。着目点は次の3つです。

「404 の件数が一番多い相手」が攻撃者とは限らない点にも注意します。単にワードリストで巡回しているスキャナは 404 を大量に出しますが、何も取れていないことが多い。むしろ「200 を返した ../ 付きの要求」を出した相手こそ、実害につながっています。

なぜ「../ を除去する」だけでは防げないのか

「入力から ../ を取り除けばよい」という発想は、拒否リスト(ブラックリスト)方式です。これは「消すべき危険な表記」を、防御側があらかじめ数え上げられている範囲でしか働きません。同じ「一つ上へ」を意味する表記は多数あります。

一箇所でも数え漏らせば、そこが穴になります。除去処理を一度通したあとにデコードが走ると、除去をすり抜けた表記が復活することもあります。だから「危険を列挙して消す」方向ではなく、次の「安全を確かめる」方向で守ります。

根本対策

base = os.path.realpath(BASE_DIR)
target = os.path.realpath(os.path.join(base, param))

# 正規化後の経路が、基準ディレクトリの内側にあるかを検査する
if not target.startswith(base + os.sep):
    abort(403)  # 外を指していたら拒否
return send_file(target)

情報処理安全確保支援士 試験での問われ方

午前Ⅱでは、脆弱性の種類の識別(ディレクトリトラバーサルと、SQL インジェクション・OS コマンドインジェクションの区別)が問われます。いずれも「利用者からの文字列を、解釈される場所へそのまま渡した」点は共通で、渡した先が何か(ファイルパスか、SQL か、シェルか)で名前が変わる、と整理すると覚えやすいです。午後問題では、アクセスログの断片を読ませ「攻撃の種類」「成功したか否か」「流出した情報」「対策」を記述させる形が多く、応答コードと応答サイズ、要求に含まれる相対経路が根拠になります。対策の記述では、暫定対策(設定変更で経路を断つ)と恒久対策(実装で正規化と検査を入れる)の書き分けが求められます。

実際に出た形を見ておきます。令和5年度 秋期 午前Ⅱ 問1 は、「入力した文字列が PHP の exec 関数などに渡されることを利用し、不正にシェルスクリプトを実行させる」攻撃がどれに分類されるかを問うものでした。選択肢には HTTP ヘッダインジェクション・OS コマンドインジェクション・CSRF・セッションハイジャックが並びます。答えは OS コマンドインジェクションですが、ここで効くのは攻撃名の暗記ではなく「渡した先はシェルか、SQL か、ファイルパスか」という切り分けです。ファイルパスに渡っていればディレクトリトラバーサル、という同じ物差しで判断できます。

令和5年度 秋期 情報処理安全確保支援士試験 午前Ⅱ の問題冊子3ページ。問1 で、入力した文字列が PHP の exec 関数などに渡されて不正にシェルスクリプトが実行される攻撃の分類が問われている
出典:令和5年度 秋期 情報処理安全確保支援士試験 午前Ⅱ 問1(IPA) 問題冊子 3 ページを掲載(同じページに問2・問3 も載っています)

IPA 公式 PDF:令和5年度 秋期 午前Ⅱ問題(問1 が脆弱性の識別) ↗解答例と採点講評も公式サイトで公開されています。

IPA 公式:過去問題(情報処理安全確保支援士試験) ↗各年度の問題冊子・解答例・採点講評の PDF を、公式サイトで確認できます(本文の転載はしていません)。

確認しておきたいこと

演習(支援士日誌)で手を動かす →