Shikata Ga Nai

Private? There is no such things.

ファイルタイプ検証の欠陥(続編):MIMEタイプ信頼による脆弱性

Hello there, ('ω')ノ

✅ サイトがやりがちな誤ったファイル検証方法

多くのWebサイトではファイルアップロードの際に Content-Typeヘッダー(MIMEタイプ) を確認することで アップロード可否を判断しています。

🎯 例:画像ファイルのみ許可したいケース

Content-Type: image/jpeg

Content-Type: image/png

のみを許可。


⚠️ しかしこの方法には重大な欠陥がある!

🎭 Content-Typeは信頼できない

  • この値は クライアント(ブラウザや攻撃者)側が自由に設定できます。
  • Burp Suite や Repeater などを使えば 簡単に偽装できます。

📚 攻撃者の例

Content-Type: image/jpeg

と偽装しながら 実際のファイルはPHPスクリプトshell.php を送信。


✅ サーバー側がMIMEタイプだけを見ていると…

  1. サーバーは image/jpeg と認識 → 問題なしと判断
  2. 実ファイルはPHP → アップロード完了
  3. 攻撃者がURLから直接アクセス
  4. サーバーが shell.phpスクリプトとして実行RCE発生

🧠 攻撃者のバイパス戦略

手法 説明
Content-Type偽装 application/x-phpimage/jpeg に変更
拡張子偽装 shell.jpg.php, image.pHp など
Content-Disposition偽装 フォームデータ内のファイル名やフィールド名を変更

✅ 安全な検証に必要なこと

1️⃣ マジックバイト(Magic Number)の確認

  • 実ファイルの先頭バイト(例:JPEGなら FF D8 FF)をチェック
  • 本物の画像データかどうかをサーバー側で確認

2️⃣ 二重検証

  • 拡張子 + MIMEタイプ + マジックバイト をすべて確認
  • どれか1つでも不一致ならアップロード拒否

3️⃣ 実行権限のない領域に保存

  • uploads/files/ ディレクトリを PHPやJSPの実行不可に設定

🎯 まとめ:MIMEタイプ信頼の危険性

サーバー側の誤信 攻撃者の悪用方法
Content-Typeだけで検証 任意のContent-Typeで偽装可能
拡張子チェックが甘い .jpg.php.pHp によるバイパス
実ファイル内容未検証 PHPやJSPスクリプトを画像としてすり抜け

✅ 結論

  • 「Content-Typeを信じる=攻撃者を信じる」
  • 安全なファイル検証には 実ファイルの構造・内容まで検証することが不可欠

「攻撃者はいつでも自由にContent-Typeを偽装できる」 サーバー側の安全設計では 「外部から送られたデータはすべて疑う」 ことが鉄則です。

Best regards, (^^ゞ