パストラバーサルは、ファイルパスにユーザー入力を使う箇所で、想定した領域の外のファイルを読み書きされる脆弱性です。 対策の勘所は、入力からパスを組み立てず、正規化と許可リストで安全な範囲に閉じ込められているかどうかです。
パストラバーサルとは
パストラバーサル(ディレクトリトラバーサル):ファイル名やパスにユーザー入力を使う際、../のような相対パスで基準ディレクトリの外へ抜け出され、意図しないファイルにアクセスされる脆弱性です。
入力をそのままパスに連結する設計が根本原因になります。
攻撃者は../../etc/passwdのような入力で、公開してよい領域の外にあるファイルを読み取ります。
設定ファイルや認証情報の漏洩、書き込みが可能なら任意ファイルの上書きによる改ざんやコード実行に至ります。
読み取りだけの機能に見えても、ソースコードや鍵、他ユーザーのファイルが抜かれるため、影響を軽く見積もれません。
パストラバーサルが起きるパターン
典型的な弱点は次のとおりです。
- ダウンロードや画像表示で、ファイル名のパラメータを基準ディレクトリに連結してそのまま開いている
- アップロードの保存先ファイル名にユーザー入力を使い、
../で保存位置をずらされる ../だけを除去する対策で、....//や多重エンコード、絶対パス指定をすり抜けられる- テンプレートや設定ファイルの読み込みパスを、外部入力で指定できてしまう
- URLのエンコードや末尾のヌルバイトなどで、拡張子チェックや除去処理をすり抜けられる
- ZIPなどアーカイブの展開時に、エントリ名のパスを検証せず外部へ書き出す(zip slip)
共通するのは「ユーザー入力がパスの構造に影響し、基準ディレクトリの外を指せてしまう」という点です。
対策法
原則は「入力をパスに直接使わず、正規化したうえで許可された範囲に収まっているか検証する」ことです。
- パスを正規化(絶対パスに解決)してから、基準ディレクトリ配下に収まっているか確認する。これが本命の対策になる
- 参照できるファイルを許可リストや固定のマッピングで管理し、入力は選択肢の識別子にとどめる
- ユーザー入力はIDとして受け取り、実ファイルのパスはサーバ側の対応表から解決する
- アップロードファイルはサーバが生成した安全な名前にリネームして保存する
- アーカイブ展開時は各エントリの展開先が基準ディレクトリ内かを検証する
../の除去だけに頼る方法は回避されやすく、本命は正規化後の範囲チェックと許可リストです。
ファイルパスに外部入力を使う箇所を洗い出し、ID経由の解決へ寄せるのが費用対効果の高い進め方になります。
Rails での事例
危険な実装は、ファイル名のパラメータを基準ディレクトリに連結してそのまま send_file に渡す形です。
# 危険:name に "../" を含めると基準ディレクトリの外を読める
def download
send_file Rails.root.join("storage/reports", params[:name])
end
Rails.root.join はパスを連結するだけで、../ を無害化してはくれません。
記事本文の原則どおり、正規化してから範囲を検証します。
REPORTS_DIR = Rails.root.join("storage/reports").to_s
def download
path = File.expand_path(params[:name], REPORTS_DIR)
unless path.start_with?(REPORTS_DIR + File::SEPARATOR)
raise ActionController::RoutingError, "Not Found"
end
send_file path
end
File.expand_path が ../ や絶対パス指定を解決した最終的なパスを返すので、その結果が基準ディレクトリ配下かを前方一致で確認します。
ディレクトリ構造を受け付ける必要がないなら、File.basename(params[:name]) でディレクトリ部分を丸ごと落とす方が単純で確実です。
構造としてより安全なのは、ファイルを Active Storage やデータベースのレコード経由で扱い、URL にはレコードの ID だけを出す設計です。 入力が「パス」ではなく「ID」になれば、パスの構造に触れる余地そのものがなくなります。
まとめ
パストラバーサル対策の要点を整理します。
- 根本原因は「ユーザー入力がパスの構造に影響し、基準ディレクトリの外を指せること」。入力をそのままパスに連結する箇所が危険の中心になる
../の除去だけでは....//や多重エンコード、絶対パス指定で回避される。本命は正規化(絶対パス解決)後の範囲チェック- より根本的なのは、入力を「パス」ではなく「ID」にする設計。実ファイルのパスはサーバ側の対応表から解決する
- アップロードはサーバ生成の名前にリネームして保存する。アーカイブ展開では各エントリの展開先を検証する(zip slip対策)
- Rails なら
File.expand_pathで解決してから基準ディレクトリ配下かを前方一致で確認する。ディレクトリ指定が不要ならFile.basenameで落とすのが単純で確実
ダウンロード・画像表示・アップロード・帳票出力など、ファイルパスに外部入力が関わる機能の棚卸しが点検の出発点です。ID経由の解決に寄せられる箇所から順に潰していくのが着実な進め方です。
関連して読める記事
「入力をIDとして受け取り、実体への解決はサーバ側で行う」という対策の型は、IDOR(安全でない直接オブジェクト参照)の対策と共通しています。参照先がファイルかデータベースのレコードかの違いで、権限とあわせて整理すると理解が深まります。また、「入力が構造として解釈される」という原因の構図はOSコマンドインジェクションと同型です。サーバ内のファイルが読み取られるという被害の面では、XMLパーサ経由で成立するXXE(XML外部実体参照)も同じ結果に至ります。

IDOR(安全でない直接オブジェクト参照)とは?起きるパターンと対策法
IDOR(安全でない直接オブジェクト参照)の仕組みと起きるパターン、所有者チェックを軸にした対策を整理します。RailsのOrder.find(params[:id])がそのまま穴になる理由と、current_user起点の取得への直し方を具体的なコード例で示します。OWASP API Security Top 10で1位のBOLAに相当する脆弱性です。
2026年7月23日
OSコマンドインジェクションとは?起きるパターンと対策法
OSコマンドインジェクションの仕組みと起きるパターン、シェルを介さず多引数形式でコマンドと引数を分離して渡す対策を整理します。Railsで system にユーザー入力を連結した文字列を渡してしまう危険例と、多引数形式での安全な実装、オプション解釈の残余リスクや Shellwords.escape の位置づけまで具体的なコードで示します。
2026年7月24日
XML外部実体参照(XXE)とは?起きるパターンと対策法
XML外部実体参照(XXE)の仕組みと起きるパターン、XMLパーサの外部実体解決とDTD処理の無効化を軸にした対策を整理します。Nokogiri の noent オプションが名前に反して実体を展開してしまう危険例と、安全な既定設定を外さない運用、SVGやOfficeファイル経由の見落としやすい経路まで具体的に示します。
2026年7月24日