コンテンツへスキップ
DedicatedPHP 接触

PHPでのファイルアップロード:エンドツーエンドの安全設計

実際の検証、隔離、ダウンロード権限、トレーサビリティ、復旧テストを備えたPHPのファイルアップロードを設計します。

受信と隔離から認可済みダウンロードまでの、PHPにおける安全なファイルアップロードフローの編集図

PHPでの安全なファイルアップロードは、フォームを受け付けてファイルをサーバーへ移動するだけではありません。添付ファイルは、実行経路、情報漏えい、リソースを枯渇させる負荷、あるいは業務プロセスで必要なときにアクセス不能な文書になり得ます。設計では、受信、検証、保存、処理、アクセス認可、監査、削除まで、ライフサイクル全体を対象にする必要があります。

ファイルを受け付ける前に業務契約を定義する

ファイルを受け付ける前に業務契約を定義する — guía visual de DedicatedPHP

最初の制御は技術的なものではありません。各添付ファイルがどのニーズを満たすのかを限定することです。本人確認書類、請求書、プロフィール画像では、形式、所有者、保存期間、参照権限が異なります。これらを汎用的な「ファイルをアップロード」機能にまとめると、適切な制御を適用しにくくなります。

文書タイプごとに、明示的な契約を定義してください。

  • 必要な形式と除外する形式。
  • 最大サイズ、操作あたりの添付ファイル数の上限、アカウントまたは案件ごとの累積クォータ。
  • 誰が、プロセスのどの状態でアップロードできるか、また置換または削除できるか。
  • 必要な自動検証と人手によるレビュー。
  • 誰が閲覧、ダウンロード、または新しいバージョンを要求できるか。
  • 保存期間と、削除をトリガーするイベント。

この契約により、「念のため」のファイル受け付けを防げます。また、ユーザーが修正できる検証エラーと、案件がすでにクローズされている状態で文書を添付しようとするなどの業務上の制約を区別できます。

拡張子と申告されたタイプだけでは不十分な理由

元のファイル名の拡張子と$_FILES['type']で送信されるタイプは、クライアントが提供するデータです。これらはインターフェース上の補助情報にはなりますが、内容を証明するものではありません。ファイルのリネームは容易であり、クライアントは任意のHTTPヘッダーを送信できます。

技術的な検証には、多層防御を用いる必要があります。PHPでは、finfoなどの仕組みで受信したバイト列からタイプを検出し、その後、リスクまたは用途に応じて形式固有のバリデーターを適用します。表示する画像では、画像として識別するだけでは不十分です。適切なライブラリでデコードし、新しい表現を生成することが推奨されます。PDFやオフィス文書では、隔離された環境で専門ツールを使用し、想定される構造を検証してください。

許可リストは拒否リストより安全です。ユースケースがJPEGとPNGを許容するなら、危険な形式を列挙しようとするのではなく、それ以外を拒否します。圧縮ファイルには追加の制御が必要です。圧縮後サイズの上限は、展開時の膨張を制限しません。展開後サイズ、エントリ数、ネストの深さ、解析時間に上限を設定してください。

名前も信頼できません。パス、識別子、物理名として使用しないでください。../のようなシーケンス、制御文字、二重拡張子、名前の衝突は、システムが独自の不透明な識別子を生成することで意味を持たなくなるべきです。

制御された受信と部分エラーの管理

内容を処理する前に、入力面を制限してください。PHP、Webサーバー、リバースプロキシで整合した上限を設定します。プロキシが100MBを受け付けるのにPHPが10MBしか許可しなければ挙動は混乱し、PHPが想定以上を許可すれば、攻撃者はメモリ、一時ディスク、ワーカー接続を消費できます。

個別サイズ、リクエスト全体のサイズ、ファイル数、アップロード時間を明示的に制御してください。$_FILESの各エントリのエラーコードを確認し、HTTPアップロード由来であることを検証し、各添付ファイルを独立した単位として扱います。複数ファイルの操作では、結果をアトミックにするか部分的にするかを事前に決めてください。部分結果を許可する場合、応答では、どのファイルを受信し、どれを拒否し、その理由は何かを正確に示しつつ、サーバー内部の詳細は公開しない必要があります。

リクエストにより制御されるパスから直接ファイルを処理したり、中断されたアップロードが無害だと信頼したりしてはいけません。不完全な一時ファイルは削除し、製品がサポートする場合は再試行を冪等にします。操作トークンまたは冪等性キーにより、ネットワーク再送後に同等の添付ファイルが複数作成されることを防げます。

非公開ストレージ、隔離、処理

バイナリをアプリケーションの公開ディレクトリ配下に置いてはいけません。最小権限の認証情報を使った非公開ストレージに保存し、各オブジェクトをシステム生成の内部識別子に関連付けます。データベースには、所有者、業務コンテキスト、検出されたタイプ、サイズ、暗号学的ハッシュ、状態、日時、保持ポリシーなどのメタデータを保持できます。名前や運用ログに不要な個人データを保存しないでください。

堅牢なフローでは、受信と利用可能化を分離します。

  1. アプリケーションがファイルを受信し、pendienteまたはen_cuarentena状態のレコードを作成します。
  2. バイナリをダウンロードできない場所に格納します。
  3. 非同期プロセスがマルウェア解析、詳細な検証、変換、または許可された抽出を実行します。
  4. 結果をdisponiblerechazado、またはrequiere_revisionへ変更します。
  5. インターフェースは、アップロード済みのファイルがすでに利用可能であるかのように装わず、運用上の状態を表示します。

キューは応答時間を短縮しますが、重複ジョブ、遅延メッセージ、停止したワーカーといった固有の障害ももたらします。冪等なタスク、再試行上限、滞留項目のアラート、制御された再処理経路を設計してください。解析を利用できない場合、安全な代替策は通常、添付ファイルを公開せず隔離状態に維持することです。

各ダウンロードを認可し、実行させずにコンテンツを配信する

誰かが識別子を知っているからといって、アクセス権が与えられるわけではありません。各ダウンロードでは、認証済みの本人、そのリソースとの現在の関係、業務コンテキストを確認する必要があります。組織への所属、案件への割り当て、現在のロール、文書の状態、時間的制約が対象です。ファイルのアップロード時に存在した認可を再利用しないでください。後から権限が取り消されている可能性があります。

ダウンロードは、オブジェクトを読み取る、または委譲する前に、この判定を適用するコントローラーを経由する必要があります。署名付きURLは外部ストレージから配信する際に有用ですが、限定されたスコープ、短い有効期限、未認可リソースに対して発行されないようにする制御が必要です。

アクティブなタイプは慎重に配信してください。ブラウザーでレンダリングする目的ではない文書には、Content-Disposition: attachmentを使用します。コンテンツタイプは拡張子ではなく検証済みタイプから設定し、X-Content-Type-Options: nosniffを追加します。プレビューは単なる埋め込みダウンロードではありません。変換済みの表現を使用し、潜在的にアクティブなコンテンツを隔離し、内部パスの公開を避ける必要があります。

本番導入前の監査、復旧、テスト

本番導入前の監査、復旧、テスト — guía visual de DedicatedPHP

作成、置換、状態変更、ダウンロード、削除、解析エラー、権限変更といった関連イベントを記録します。ログにはアクター、時点、リソース、結果を含めるべきですが、バイナリや重複する機密データを保存する必要はありません。これらのイベントを改ざんから保護し、誰が参照できるかを定義してください。

復旧には、ストレージ、データベース、またはプロセッサが失敗した場合に何が起きるかを把握する必要があります。バイナリとそのメタデータの整合性が取れるまで、文書を利用可能としてマークしないでください。オブジェクトのないレコード、孤立オブジェクト、隔離状態に長時間留まる項目を検出するための照合タスクを設計します。

リリースチェックリスト

  • 許可する形式は文書化されたユースケースに対応し、内容に基づいて検証される。
  • サイズ、数量、時間、圧縮ファイルの展開に上限がある。
  • 元の名前がパスや物理名を決定しない。
  • バイナリは公開ディレクトリ外に保存され、該当する場合は隔離を経由する。
  • ダウンロード時に認可を再評価し、内部パスを公開しない。
  • 不正な形式のファイル、重複、中断されたアップロード、取り消された権限、ストレージ障害をテストする。
  • 拒否、滞留ジョブ、配信エラー、消費容量を監視している。
  • 保持、削除、監査ポリシーには運用責任者がいる。

アップロードを状態と制御を備えたフローに変えることは、アップロード用ディレクトリを使うよりコストがかかるように見えるかもしれません。しかし、不審なファイル、アクセスに関する申し立て、運用中断が発生した際の場当たり的な判断を減らせます。このトレーサビリティは後付けではなく、製品の一部です。

これらのアイデアをあなたのプロジェクトに活用してみませんか?あなたのPHPプラットフォームについて話し合いましょう。
関連サービスを見る