「画像ファイルです」という嘘を見破れ!安全なファイルアップロードの鉄則
こんにちは。現場の最前線でシステムの守りを固めているエンジニアです。
皆さんは、Webサイトでプロフィール画像などをアップロードする機能を作ったことはありますか? 実は、この何気ない「ファイルのアップロード」という機能は、ハッカーたちにとって「システムの中に入るための黄金の鍵」になり得ます。
今日は、初心者の方が最初にぶつかる壁であり、かつ最も重要な「ファイルの偽装」を見破るための防御術について、身近な例えを交えてお話ししますね。
—
泥棒は「お土産」を持ってやってくる
まず、なぜファイルアップロードが危険なのかを考えてみましょう。
想像してみてください。あなたは自分の家の玄関に「手紙受け」を設置しました。誰でも自由に封筒を入れられる仕組みです。ところが、ある日悪い泥棒が、封筒の中に「家の中を勝手に操作できる魔法の呪文(悪意のあるプログラム)」を忍ばせて投函しました。
あなたが「これは手紙だ」と信じてその封筒を開いた瞬間、家の中の金庫が勝手に開いてしまったら……怖いですよね?
Webの世界でも同じです。攻撃者は、「.php」や「.exe」のような実行プログラムを、「.jpg」という画像ファイルに見せかけてサーバーに送り込みます。もしサーバーがそれを「画像だ」と信じ込んで実行してしまったら、サーバーが乗っ取られてしまうのです。
—
「拡張子」という名の名札は信用してはいけない
多くの初心者がやりがちな最初のミスは、拡張子(ファイル名の末尾の .jpg など)だけで判断することです。
でも、考えてみてください。泥棒が自分の名前を「郵便屋さん」と書いた名札を胸につけていたら、あなたは疑わずにドアを開けてしまいますよね? 拡張子とは、まさにその「自分で書いた名札」のようなもの。攻撃者はいくらでも偽造できます。
そこで、我々プロが必ず行うのが「マジックナンバー(ファイルシグネチャー)の確認」です。
—
マジックナンバー=「ファイルのDNA」
すべてのファイルには、人間には見えないファイルの先頭部分に、そのファイルの「正体」を示すバイナリデータ(16進数の羅列)が書き込まれています。これをマジックナンバーと呼びます。
例えば、JPEG画像なら必ず先頭が FF D8 FF から始まります。これはファイル名を変えようが、拡張子を偽装しようが書き換えることはできません。いわば、DNA鑑定のようなものです。
実装のポイント:PHPでの安全な検証例
では、実際にどうやって実装するか見てみましょう。ここでは、ファイル名ではなく「中身」を検査する方法を紹介します。
file($file);
// 2. 許可するMIMEタイプをホワイトリストで定義
$allowed_types = [‘image/jpeg’, ‘image/png’, ‘image/gif’];
if (!in_array($mime_type, $allowed_types)) {
// 中身が画像じゃないなら、即座に拒否!
die(“不正なファイル形式です。画像のみアップロード可能です。”);
}
// 3. この後に名前をランダムな文字列に変換して保存する処理などを追加します
// ※元のファイル名を使うのは厳禁です!(ディレクトリトラバーサル攻撃の原因になります)
echo “アップロード成功!”;
?>
なぜこれだけで安全になるのか?
1. 中身を見ている: 拡張子が .jpg でも、中身がプログラムなら image/jpeg とは判定されません。
2. ホワイトリスト方式: 「許可リスト」に載っていないものはすべて拒否する。これがセキュリティの鉄則です。「これ以外はダメ」というスタンスを貫きましょう。
—
さらに一歩進んだ対策:「保存先」を殺菌する
マジックナンバーの確認は必須ですが、それだけで100%安心とは言い切れません。最後に、もう一つの「守り」を伝授します。
それは、「アップロードされたファイルを直接実行させない」ことです。
- 保存先ディレクトリの実行権限をオフにする: Webサーバー(ApacheやNginx)の設定で、アップロード先フォルダ内でのプログラム実行を許可しないように設定します。
- ファイル名を書き換える: ユーザーが送ってきたファイル名をそのまま使わず、システム側で
uniqid()などを使ってランダムな名前に変更して保存します。
—
最後に:セキュリティは「疑うこと」から始まる
「便利に使えること」と「安全であること」は、しばしばトレードオフの関係にあります。
でも、今回お話しした「中身をちゃんと確認する」というひと手間を加えるだけで、あなたのシステムは格段に強固になります。新人エンジニアの皆さんも、ぜひ今日から「ユーザーが送ってくるデータは、すべて泥棒の変装かもしれない」という疑いの目を持って、コードを書いてみてください。
一歩ずつ、丁寧に。それが世界最高峰のセキュリティへの第一歩です。また次の記事でお会いしましょう!
コメント