【ファイルアップロード編】画像だけでも危険?保存と検証の守り方|CTF思考フレームワーク #06
こんにちは、アンペンです!
前回は、お問い合わせフォームが「運営者の足元」に届くがゆえに狙われる話をしました。
今回は、利用者から「物」を受け取る入口、ファイルアップロードを見ていきます。「ただの画像を送るだけ」が、なぜサーバー乗っ取り(RCE)の入口になりうるのかを学びましょう。

画像を送るだけで、サーバーが乗っ取られるなんてあるの?

『画像のフリをしたプログラム』を送られると、保存場所と扱い方によってはサーバー上で実行されてしまうことがあるんだ。
『画像を投稿するだけ』の機能が、まさかサーバー乗っ取りにつながるなんて——初めて聞くとちょっと信じられないですよね。でもこれは、CTFでも実務でも本当によくある王道パターンなんです。今日は「なぜ画像のフリをしたファイルが危ないのか」を、宅配便のたとえも使いながら、こわがらずに一歩ずつほどいていきましょう。
ファイルアップロードは「拡張子」「MIMEタイプ」「保存場所」「実行可否」のどれかを誤ると、画像のフリをした実行ファイルでサーバーが乗っ取られる(RCE)入口になります。
この記事で分かること
- 「画像に見える危険なファイル」の代表的なパターン
- 二重拡張子・MIME偽装が成立する仕組み
- 演習環境での観察方法と、守る側の基本対策
📖 はじめてのWebセキュリティ #06|ファイルアップロード編
「画像投稿」のような身近な機能から、サーバー実行へつながる経路と、その断ち方を学びます。 シリーズ一覧を見る →
⚠️ 大事なお約束
この記事の確認は、CTF・公式ラボ・自分で作った検証環境だけで行ってください。実在するサービスに、実行可能ファイルを偽装してアップロードする行為は絶対にしないでください。
ファイルアップロードは「中身」と「置き場」の両方が重要
ファイルアップロードのセキュリティでは、「何を受け取ったか」と「どこに置いたか」の両方を見る必要があります。
受け取ったファイルが画像と見せかけた実行ファイルでも、サーバーが「ただのデータ」として扱う場所に保存されていれば、問題は起こりません。しかし、Web経由でアクセスできて、なおかつサーバー側で実行される設定の場所に置かれてしまうと、攻撃の入口になります。
ここがこの回の心臓部なので、もう少しゆっくり。ポイントは『置き場所しだいで運命が変わる』ことです。同じ怪しいファイルでも、ただのデータ置き場(サーバーが中身を“読むだけ”の場所)にあるなら、ほぼ無害。ところが、Webからアクセスできて、しかもサーバーが“プログラムとして動かす”設定の場所に置かれると、その瞬間に牙をむきます。だから「何を受け取るか」と同じくらい「どこに置くか」が大事なんです。
まず大前提として知っておきたいのが、『拡張子(.pngや.jpg)は、ただのラベルにすぎない』ということです。ファイルの本当の中身とは、実は何の関係もありません。たとえるなら、お弁当の包み紙に「サラダ」と書いてあっても、中身がから揚げかどうかは開けてみないと分からないのと同じ。攻撃者はこの“ラベルと中身のズレ”を悪用してきます。
図解:拡張子と中身が一致しないファイル

「拡張子」と「ファイルの中身」は、別々に偽装できます。普通の画像と、偽装されたファイルの違いを見ておきましょう。
つまり攻撃者は、見た目(拡張子)も、自己申告(MIME)も、両方そろえて“完璧な画像のフリ”ができてしまうということ。だからこそ、表面の情報だけで判断せず、実際にファイルを開いて中身を検証する一手間が、ここでは効いてきます。

宅配の伝票に「本」と書いてあっても、箱を開けるまで本物の本かどうかは分かりません。仮に中に時限装置が入っていても、伝票だけ見ていたら気づけません。受け取り側は、伝票(拡張子)と中身(実際のデータ)を別々に確認する仕組みが必要です。
ここで覚える用語:MIMEタイプ
ファイルの「種類」を示す情報で、ブラウザやサーバーが「これは画像」「これはHTML」のように判断する材料です。クライアント側で自由に書き換えられるため、サーバーで実際の中身も再確認する必要があります。
MIMEタイプも、さっきの拡張子と同じで“自己申告”にすぎない、というのがミソです。ファイルを送る側が「これは image/png です」と名乗っているだけで、本当にそうかは保証されていません。受付で「私は配達員です」と口で言われても、ふつうは制服や伝票を確かめますよね。サーバーも同じで、申告を鵜呑みにせず、中身を自分の目で再確認する必要があるんです。
アップロードから狙われる代表的な3パターン
アップロードから狙われる入口は、大きく3つです。『拡張子を二重にする』『MIMEを偽る』『保存先をずらす』。名前はいかついですが、やっていることはどれも“ラベルや宛先をごまかして、本来は置かれないはずの場所に潜り込む”こと。順番に、絵本をめくる感じで見ていきましょう。
代表的な攻撃の入口

- 二重拡張子:「photo.png.php」のように、画像のフリをしたスクリプトを送り込み、サーバー実行を狙う
- MIME偽装:送信時のMIMEを「image/png」に偽り、受け取り側に画像と誤認させる
- パストラバーサル:ファイル名に「../」を混ぜて、想定外の場所に保存させる
これらは、サーバー側の保存先設定や、Webサーバーの実行設定と組み合わさることで、画像投稿機能から最終的にRCE(任意コード実行)に到達することがあります。
『RCE』という言葉が出てきました。これは Remote Code Execution の略で、ひとことで言えば“攻撃者が、あなたのサーバーの上で好きなプログラムを動かせてしまう”状態のこと。これはWebセキュリティでもっともマズいゴールのひとつです。なぜなら、いったんサーバーで自由にプログラムを動かせれば、データの抜き取りも、改ざんも、ほかのサーバーへの侵入も、ほぼ何でもできてしまうから。『画像投稿』というやさしい入口から、最悪ここまで到達しうる——だからこそ侮れないんです。
ここまで読むと、つい『自分でも試してみたい』と思うかもしれません。その好奇心は大切ですが、必ず自分の演習環境かCTFの中だけにしてください。本物のサービスに実行ファイルを偽装して送るのは、それ自体が攻撃行為で、法律にも触れます。安全な砂場の中で「拡張子と中身がズレると、サーバーはどう反応するか」を眺めるだけで、学びとしては十分です。
CTFでやってみよう:アップロードの扱い方を観察する
テスト用ファイルを使って、保存先と表示挙動を確認しよう
目的は攻撃成立ではなく、「拡張子と中身が違うとサーバーはどう反応するか」を観察することです。
- CTFや自分の検証環境のアップロード機能で、普通の画像(.png)を送信し、保存先のURLを確認する
- テキストファイルの拡張子だけ.pngに書き換えて送り、サーバーがどう扱うか観察する
- ファイル名に空白や日本語、長い名前を含めたとき、保存名がどう変換されるかを確認する
- 保存されたファイルのMIMEタイプが、サーバーの応答ヘッダにどう出ているかを見る
- 同名ファイルを再アップロードしたとき、上書きされるか連番が付くかを観察する
演習で試すと、『拡張子を.pngにしただけのテキストファイル』をサーバーがどう扱うかが見えてきます。素直に画像として開こうとして失敗するのか、中身を読んできっぱり弾くのか——その反応の差が、守りの強さをそのまま映しています。では、守る側はどんな手を打てばいいのか。キーワードは『受け取り・保存・配信・実行抑止』の4点セットです。

受け取った画像を、わざわざ作り直す(再エンコード)の?そのまま保存じゃダメなの?

いい質問!画像をいったんバラして作り直すと、中にこっそり仕込まれたプログラムの“かけら”が物理的に消えるんだ。料理でいえば、もらった食材を全部下ごしらえし直すようなもの。見た目は同じ画像でも、危ない部分はちゃんと落ちている——これがすごく効くんだよ。
守る側なら、4つの観点で固めよう
ファイルアップロードを守るには、「受け取り」「保存」「配信」「実行抑止」の4つを組み合わせるのが基本です。
- 許可する拡張子・MIMEはホワイトリスト方式で限定する
- 受け取った画像はサーバー側で再エンコードし、悪意あるデータを物理的に落とす
- 保存ファイル名はサーバーで再生成(UUIDなど)し、利用者の入力名をそのまま使わない
- 保存先はWeb公開ディレクトリと分け、配信は別ドメインや専用ハンドラー経由にする
- WebサーバーやPHP設定で、保存ディレクトリでのスクリプト実行を禁止する
- サイズ上限・同時アップロード制限・ウイルススキャンを組み合わせる

「拡張子だけ見る」では足りないんだね。

そう。中身の検査と、置き場の設計、両方が揃って初めて安全になるよ。
念のため繰り返しますが、守りは“一枚岩”だと破られます。たとえ拡張子チェックをすり抜けられても、保存先でスクリプト実行が禁止されていれば、被害は出ません。ホワイトリスト・再エンコード・実行禁止——どれか一つに頼るのではなく、何枚も重ねるからこそ強いんです。「ここさえやれば安心」という一発の対策はない、と覚えておきましょう。
まとめ:アップロードは「中身」と「置き場」の二重チェック
- 拡張子とMIMEはクライアント側で偽装可能。サーバーで再確認する
- 二重拡張子・MIME偽装・パストラバーサルがRCEの入口になる
- CTFでは、拡張子と中身の不一致に対してサーバーがどう反応するか観察する
- 守る側は受け取り・保存・配信・実行抑止の4観点で固める
今日の持ち帰りは『拡張子は信じない、中身と置き場で守る』。ファイル名やMIMEはいくらでも偽れるので、サーバー側で中身を確かめ、たとえ悪いものが紛れ込んでも“動けない場所”に置く。この二段構えを思い出せれば、アップロード機能はぐっと安全に作れます。便利な投稿機能と安全は、ちゃんと両立できるんです。
次回は、ファイル送信の流れの中でも「利用者自身の情報を更新する」プロフィール編集を扱います。IDORやマスアサインメント、保存型XSSの罠を見ていきましょう。
