ファイルアップロード

File Upload Cheat Sheet

原典
File Upload Cheat Sheet(OWASP Cheat Sheet Series)
原文
GitHub 上の Markdown
底本
bac04fb5(2026-07-29 時点)
ライセンス
CC BY-SA 4.0(原典と同一。訳文も同ライセンスで再配布できます)

はじめに

ファイルアップロードは、どのアプリケーションでも次第に欠かせない機能になっている。 利用者は写真、履歴書、取り組んでいるプロジェクトを紹介する動画などをアップロードする。 アプリケーションは、アプリケーション自身と利用者の安全を保つ形で、偽装されたファイルや悪意あるファイルを退けられなければならない。

要するに、安全なファイルアップロードの実装に至るには次の原則に従う。

  • 許可する拡張子を列挙する。業務上必要で安全な拡張子のみを許可する
    • 拡張子の検証の前に入力検証が適用されている状態にする。
  • ファイルの種別を検証する。Content-Type ヘッダは偽装できるので信用しない
  • ファイル名をアプリケーションが生成したものに変える
  • ファイル名の長さの上限を設ける。可能であれば使える文字も制限する
  • ファイルサイズの上限を設ける
  • 認可された利用者のみにアップロードを許す
  • ファイルは別のサーバーに保存する。それが不可能なら Web の公開ルートの外に保存する
    • ファイルを一般公開する場合は、アプリケーション内部でファイル名に対応づけられるハンドラを用いる(someid → file.ext)
  • 利用できるならウイルス対策やサンドボックスにファイルを通し、悪意あるデータを含まないことを検証する
  • 該当する種別(PDF、DOCX など)であれば CDR(Content Disarm & Reconstruct)にファイルを通す
  • 利用するライブラリが安全に設定され、最新に保たれている状態にする
  • ファイルアップロードを CSRF 攻撃から保護する

ファイルアップロードの脅威

どの対策を実装すべきかを的確に見極めるには、何に直面しているのかを知ることが資産の保護に不可欠である。 以下の節は、ファイルアップロード機能に伴うリスクを示す。

悪意あるファイル

攻撃者は次のような悪意ある目的でファイルを送り込む。

  1. ファイルのパーサや処理モジュールの脆弱性を悪用する(ImageTrick の悪用XXE など)
  2. フィッシングにファイルを使う(採用応募フォームなど)
  3. ZIP 爆弾、XML 爆弾(billion laughs 攻撃としても知られる)、あるいは単に巨大なファイルを送り、サーバーの記憶領域を埋めて可用性を損なわせる
  4. システム上の既存のファイルを上書きする
  5. ファイルが公開されて取得可能な場合、他の利用者を危険にさらしうるクライアント側の能動的コンテンツ(XSS、CSRF など)

ファイルの公開取得

アップロードされたファイルが公開されて取得可能である場合、次の脅威も加わる。

  1. 他のファイルの公開露出
  2. 大量のファイルを要求することによるサービス妨害攻撃の実行。リクエストは小さいが、応答はそれよりはるかに大きい
  3. 違法、不快、危険とみなされうるファイルの内容(個人データ、著作権のあるデータなど)。それにより、そうした悪意あるファイルを配信する側になってしまう

ファイルアップロードの保護

利用者のコンテンツの検証に特効薬はない。 多層防御の方針を実装し、アップロードの処理をそのサービスの必要と要件に合わせて難しく、狭く固めることが鍵になる。 単一の手法ではサービスを守るのに十分でないので、複数の手法を実装することが重要であり、推奨される。

拡張子の検証

検証はファイル名をデコードしたあとに行い、次のような既知の回避手法を避ける適切なフィルタが用意されている状態にする。

  • 二重の拡張子。たとえば .jpg.php は正規表現 \.jpg を容易にすり抜ける
  • ヌルバイト。たとえば .php%00.jpg では .jpg が切り捨てられ、.php が新しい拡張子になる
  • 十分に試験も精査もされていない、雑で不適切な正規表現。この話題について十分な知識がないかぎり、独自のロジックを組むことは控える

拡張子を適切に解析して処理するには入力値の検証を参照する。

許可する拡張子を列挙する

業務上不可欠な拡張子のみを使い、必要でない種類の拡張子は一切許可しない状態にする。 たとえばシステムが次を必要とする場合はこうする。

  • 画像のアップロードであれば、業務要件に合うと合意された一つの種別のみを許可する。
  • 履歴書のアップロードであれば、docxpdf の拡張子を許可する。

アプリケーションの必要に基づき、最も害が少なく最もリスクの低いファイル種別が使われる状態にする。

拡張子を遮断する

害になりうるファイル種別を特定し、自分のサービスにとって有害とみなす拡張子を遮断する。

特定の拡張子を遮断することは、それ単体では弱い保護手段であることに注意する。 攻撃者がそうした検査を回避しようとする方法は制限のないファイルアップロードの脆弱性の記事で説明されている。

Content-Type の検証

アップロードされたファイルの Content-Type は利用者が与えるものであり、偽装が容易であるため信用できない。 安全性のためにこれに依存すべきではないが、利用者が意図せず誤った種別のファイルをアップロードすることを防ぐ手早い検査にはなる。

アップロードされたファイルの拡張子を定めることに加えて、その MIME タイプを確認すれば、単純なファイルアップロード攻撃に対する手早い保護になる。

これは許可リスト方式で行うのが望ましく、そうでなければ拒否リスト方式で行う。

ファイルシグネチャの検証

Content-Type の検証とあわせて、ファイルのシグネチャを、受け取るべき想定のファイルと照合して検証できる。

これを単体で用いるべきではない。回避はよくあることであり、容易である。

ファイル名の安全性

ファイル名は複数の形でシステムを危険にさらしうる。 受け入れられない文字を使う場合と、特殊な、あるいは予約されたファイル名を使う場合である。 Windows については MSDN の解説を参照する。 各種のファイルシステムがファイルをどう扱うかの広い概観は Wikipedia の Filename のページを参照する。

上述の脅威を避けるには、UUID や GUID を生成するなどしてランダムな文字列をファイル名にすることが不可欠である。 業務上ファイル名が必要な場合は、クライアント側の攻撃経路(XSS や CSRF につながる能動的コンテンツなど)とバックエンド側の攻撃経路(特殊なファイルの上書きや作成など)の両方に対して適切な入力検証を行うべきである。 ファイル名の長さの上限は、ファイルを保存するシステムに基づいて考慮する。 システムごとに独自の上限があるからである。 利用者のファイル名が必要な場合は、次の実装を検討する。

  • 最大長を設ける
  • 使える文字を、英数字、ハイフン、空白、ピリオドなどの許可した部分集合に明示的に制限する
    • どのようなファイル名が受け入れられるのかを利用者に伝えることを検討する。
    • 先頭のピリオド(隠しファイル)と連続するピリオド(ディレクトリトラバーサル)の使用を制限する。
    • シェルスクリプトでファイルを処理する際の安全性を高めるため、先頭のハイフンや空白の使用を制限する。
    • これが不可能な場合は、ファイルを保存して利用するフレームワークとシステムを危険にさらしうる危険な文字を拒否リストに入れる。

ファイル内容の検証

ファイルの公開取得の節で述べたように、ファイルの内容は悪意ある、不適切な、あるいは違法なデータを含みうる。

想定される種別に基づいて、内容に固有の検証を適用できる。

  • 画像では、画像の書き換え手法を適用することで、画像に注入されたあらゆる悪意ある内容が破壊される。これはランダム化によって行える。
  • Microsoft の文書では、Apache POI を使うとアップロードされた文書の検証に役立つ。
  • ZIP ファイルは推奨されない。あらゆる種類のファイルを含みうるうえ、それに関わる攻撃経路が多数あるからである。

ファイルアップロードのサービスは、利用者が違法なコンテンツを報告でき、著作権者が濫用を報告できるようにするべきである。

十分な資源があるなら、ファイルを公開する前にサンドボックス環境で人による確認を行うべきである。

確認に何らかの自動化を加えると助けになる。 ただしこれは厳しい処理であり、使う前に十分に検討するべきである。 Virus Total のようなサービスは、既知の悪意あるファイルのハッシュと照合してファイルを走査する API を提供している。 ASP.NET Drawing ライブラリのように、生のコンテンツ種別を確認し、あらかじめ定めたファイル種別と照合して検証できるフレームワークもある。 公開サービスによるデータの漏出と情報収集の脅威に注意する。

ファイルの保存場所

ファイルを保存する場所は、安全性と業務の要件に基づいて選ばなければならない。 次の各項目は安全性の優先度順であり、上位のものは下位のものを包含する。

  1. ファイルを別のホストに保存する。これにより、利用者に応答するアプリケーションと、ファイルのアップロードと保存を扱うホストとのあいだで、役割を完全に分離できる。
  2. ファイルを Web の公開ルートの外に保存し、管理者のアクセスのみを許す。
  3. ファイルを Web の公開ルートの内側に保存し、書き込み権限のみを設定する。
    • 読み取りアクセスが必要な場合は、適切な制御(内部 IP、認可された利用者など)を設けることが必須である。

検討のうえでデータベースにファイルを保存することも、追加の手法の一つである。 これは自動バックアップの処理、ファイルシステムを狙わない攻撃への対処、権限の問題への対処のために使われることがある。 その代わり、(場合によっては)性能の問題、データベースとそのバックアップの容量の考慮、そして SQL インジェクション攻撃の余地を生む。 これはチームに DBA がいて、かつファイルシステムに保存するより改善になると示される場合にのみ推奨される。

ファイルによっては、アップロードされたあとメールで送られるか処理されるだけで、サーバーに保存されないものもある。それらに何らかの操作を行う前に、このチートシートで述べた安全対策を実施することが不可欠である。

利用者の権限

ファイルアップロードのサービスにアクセスされる前に、ファイルをアップロードする利用者について二つの水準で適切な検証を行うべきである。

  • 認証の水準
    • アップロード能力に対する制限や上限を設けるため、利用者は登録済みの利用者、または身元を特定できる利用者であるべきである
  • 認可の水準
    • 利用者はファイルにアクセスまたは変更するための適切な権限を持つべきである

ファイルシステムの権限

ファイルの権限は最小権限の原則に基づいて設定する。

ファイルは次を保証する形で保存するべきである。

  • ファイルを読めるのは、許可されたシステムの利用者だけである
  • そのファイルに必要なモードのみが設定されている
    • 実行が必要な場合は、マクロや隠されたスクリプトが存在しないことを確かめるため、実行前にファイルを走査することが安全上の最良の慣行として求められる。

アップロードとダウンロードの上限

アプリケーションは、ファイルの記憶容量を守るために、アップロードのサービスに適切なサイズの上限を設けるべきである。 システムがファイルを展開または処理する場合、ファイルサイズの上限は展開後について考慮し、ZIP ファイルのサイズ計算には安全な方法を用いる。 これについてさらに詳しくは、ZIP ファイルを扱う Java の入力ストリームである ZipInputStream から安全にファイルを展開する方法を参照する。

ダウンロードのサービスがある場合は、サービス妨害攻撃からサーバーを守るために、そちらにも適切なリクエストの上限を設けるべきである。

Java のコード例

Java における特定の文書種別のための Document Upload Protection リポジトリが Dominique によって書かれている。