こんにちは!Webサービスの開発やインフラの管理、毎日お疲れ様です。新人のIT担当者さんや、「セキュリティってなんだか難しそう……」と少し不安を感じている開発者の方に向けて、今日からすぐに使える実践的なセキュリティの知識をお届けしますね。
今回は、Webアプリケーションの代表的な弱点の一つである「Path Traversal(ディレクトリトラバーサル)」について、お話ししていきます。
難しそうな名前ですが、仕組みを知れば「なるほど、だからしっかり鍵をかけなきゃいけないんだ!」とすんなり腑に落ちるはずです。一緒に一歩ずつ、防犯の仕組みを学んでいきましょう!
—
1. ディレクトリトラバーサルってどんな攻撃?(身近な例えで理解しよう)
まずは、この攻撃がどういうものなのか、私たちの日常生活に置き換えて考えてみましょう。
皆さんが住んでいるお家に、玄関のドアがあるとします。通常、郵便配達員さんは郵便受けに手紙を入れて、家の中に入ってくることはできませんよね。これは「玄関」という正しいルートを通っているからです。
でも、もし裏口の鍵が壊れていて、少し隙間が空いていたらどうでしょう? 悪意のある人が、その隙間から棒を差し込んで、隣の部屋にある秘密の金庫の鍵を開けようとしたり、別の部屋を勝手に見たりするかもしれません。
これとまったく同じことが、Webの世界でも起きるのです。
ディレクトリトラバーサルは、ユーザーが入力するファイル名(例えば profile.jpg など)の隙を突いて、サーバーの奥深くにある隠されたファイル(例えば ../../../../etc/passwd のようなシステム設定ファイル)をこっそり覗き見してしまう攻撃のことです。
ここで登場する ../ という記号は、ファイルパスの世界で「一つ上の階層のフォルダに戻る」という特別な意味を持っています。これを利用して、本来見えるはずのないフォルダへずるずると「横断(トラバスト)」していくことから、この名前がついています。
—
2. なぜ危ないの? 攻撃者が狙う盲点
新人プログラマーの皆さんが、ファイルを表示するプログラムを作るとき、こんな風に書いてしまいたくなることはありませんか?
<?php
// ユーザーが入力したファイル名をそのまま受け取ってしまっている例(危険!)
$filename = $_GET['file'];
$filepath = "/var/www/uploads/" . $filename;
// ファイルを読み込んで表示する
readfile($filepath);
?>
一見すると、「/var/www/uploads/ という安全なフォルダの中にあるファイルだけを読み込んでいるんだから大丈夫そう」に見えますよね。これが大きな盲点なんです。
もし、悪意のあるユーザーがブラウザのURLに ?file=../../../../etc/passwd と入力してアクセスしてきたらどうなるでしょうか?
プログラムは、指定されたパスをそのまま繋げて、次のように解釈してしまいます。
/var/www/uploads/../../../../etc/passwd
結果として、uploads フォルダを飛び出し、サーバーの根底にある重要なシステムファイルを読み込んで画面に表示してしまうのです。これが、ディレクトリトラバーサルが恐ろしい理由です。
—
3. 「一歩ずつ対策を学ぼう!」安全なコードの書き方
「じゃあ、どうやって守ればいいの?」という話ですよね。安心してください。しっかりとした対策の基本を知っていれば、こうした不正なアクセスをピタッと防ぐことができます。
対策の基本は大きく分けて2つあります。
1. ブラックリストではなく、ホワイトリストを使う(許可されたものだけを通す)
2. パスの正規化(正しい絶対パスへの変換)を行ってから検証する
実際のPHPコードを使って、安全な実装方法を見てみましょう。
実装サンプル:ホワイトリストと正規化による防御
<?php
// 【対策のポイント】
// 1. 許可するファイル名のリスト(ホワイトリスト)をあらかじめ定義します
$allowed_files = [
'user_guide.pdf',
'terms.pdf',
'privacy.pdf'
];
// ユーザーからの入力を受け取る
$input_file = $_GET['file'] ?? '';
// 2. 入力されたファイル名が、許可されたリストの中に完全一致するかチェックする
if (!in_array($input_file, $allowed_files, true)) {
// リストにない場合はエラーとして処理を中断する
header("HTTP/1.0 403 Forbidden");
echo "アクセスが拒否されました:不正なファイル名です。";
exit;
}
// 3. 安全なベースディレクトリ(保管場所)を明確に定義する
$base_dir = '/var/www/uploads/';
// realpath関数を使って、実際の絶対パスを組み立てる(ここでパスの正規化が行われます)
$filepath = realpath($base_dir . $input_file);
// 4. 生成されたパスが、本当に安全なベースディレクトリの配下にあるか最終確認する
// (strposを使って、パスの先頭が $base_dir から始まっているかチェック)
if ($filepath === false || strpos($filepath, $base_dir) !== 0) {
header("HTTP/1.0 403 Forbidden");
echo "アクセスが拒否されました:無効なパスです。";
exit;
}
// すべての安全確認を通過したファイルだけを読み込んで表示する
readfile($filepath);
?>
このコードでは、$allowed_files という「入れる人を制限したリスト」を作り、さらに realpath() というPHPの関数を使って、../ のような怪しい動きをすべて綺麗に打ち消す(正規化する)処理を行っています。
たとえ攻撃者が巧妙な文字列を送り込んできても、最終的なパスが正しいフォルダの範囲内におさまっているかを厳しくチェックしているため、不正な侵入をしっかりと防ぐことができるのです。
—
4. まとめ:日々の開発で意識したいこと
今回は、ディレクトリトラバーサルの仕組みと、その具体的な防御策についてお伝えしました。
- ユーザーの入力をそのまま信じない(信用しない、検証する!)
- ファイルパスを連結するときは、
../などの特殊文字による脱出を警戒する - 可能な限りホワイトリスト方式(許可されたものだけ通す)を採用する
セキュリティ対策と聞くと身構えてしまうかもしれませんが、要は「我が家の玄関の鍵をしっかり閉めて、怪しい人が来たらインター越しにお断りする」のと同じです。
日々のコーディングの中で、「この入力値、そのまま使って大丈夫かな?」と一度立ち止まる習慣をつけるだけで、あなたの作るWebサービスはぐっと安全になります。
一歩ずつ、確実にスキルアップしていきましょう!次の記事でも、すぐに役立つセキュリティの知見をお届けしますので、ぜひ楽しみにしていてくださいね。
コメント