Pillowのopen()、verify()、load()をセキュリティ観点で理解する
画像アップロードは「画像ファイルを受け取る」だけではなく、外部入力をデコーダ(パーサ)に通す作業です。そこでPillowの3つのメソッドは、機能説明よりもいつ呼び出すか(=攻撃表面をいつ開くか)が重要です。
open()は「ピクセルを上げる関数」ではない
Image.open()は遅延動作です。つまり、ファイルを「開いて識別」だけし、ピクセルデータはまだ読み込まないことがあります。また、ファイルハンドルが開いたまま残ることもあります。
セキュリティ/運用でopen()をうまく使う方法はシンプルです。
open()でフォーマット識別、幅/高さなど軽量情報を取得- ポリシーでブロック:許可フォーマット、最大解像度/ピクセル数、アップロード容量制限
- 次の段階(検証/デコード)へ進む
つまり、open()は「デコード前段階で判断できる情報を抽出するツール」として安全に使うべきです。
verify()は何を保証し、何を保証しないか
Pillowのverify()は「ファイルが壊れているか」を確認しようとしますが、実際の画像データをデコードせずに検査します。問題があれば例外を投げ、verify()後に画像を使うにはファイルを再度開く必要があります。
ここでのセキュリティ的結論は2点です。
- メリット:デコード(=重い作業)を避けつつ「壊れたファイル」を高速に除外できる
- 限界:
verify()通過は「安全」ではなく「今すぐ大きく壊れていない」に近い。デコードを完了しないため、load()時点で問題が表れる可能性があります。
load()は検証段階で無闇に呼び出すと危険
load()は実際にデコード(圧縮解凍を含む)を行い、ピクセルをメモリに上げる段階です。この点が直ちにDoS(リソース枯渇)攻撃の表面になります。見た目のファイルサイズが小さくても、デコード結果が非常に大きくなる可能性があります。
Pillowは「デコンプレッションスプリング」リスクを警告/例外で扱い、デフォルトの閾値(例:128Mpx程度)などの保護機構を持っています。
Djangoも同じ理由で、画像アップロード検証でload()ではなくverify()を使用します。ソースには「load()は全画像をメモリに上げてDoSベクターになる」というコメントがあり、実際にImage.open()後にverify()を呼び出します。
Django/DRF使用時:ImageFieldでverify()をもう一度呼ぶと重複になる
DjangoのフォームImageField検証は内部でImage.open() + verify()を実行します。DRFのserializers.ImageFieldも「Django実装に委譲する」コメント付きでDjango側検証を呼び出すフローを持ちます。
したがってDRFでserializers.ImageFieldを既に使っている場合:
- ただ「壊れたか確認」だけで
validate()内でverify()を再度呼ぶのはほぼ重複作業になります。 - ビジネス検証/追加セキュリティ検証を強くカスタマイズしたい場合は、
ImageFieldではなくFileFieldで受け取り(検証パイプラインを直接設計)コストと責任を明確にする選択がよりクリーンです。
ユーザーがアップロードしたファイルに「安全」を確保するには

最も現実的な答えはこれです。
「アップロード元をそのまま使わず、サーバーがデコードして新ファイルとして再保存した結果のみを使用する」
open()で幅/高さ/フォーマットなど低コスト情報を読み、ポリシーで一次ブロックverify()で明らかに壊れたファイルを除外- 次に(通過したもののみ)制限された環境でデコードしRGB/RGBAなど標準ピクセルへ正規化
- サーバーが選択したフォーマットで再エンコードして新ファイル生成
- サービスはサーバーが再生成したファイルのみを保存/配信
この戦略のメリットは「サーバーが最終出力の形を制御できる」点です。元ファイルにあった不要メタデータや奇妙な構造を大部分除去できます。
ただし再エンコードは結局load()に相当するデコードを含みます。
したがってピクセル数/メモリ制限(デコンプレッションスプリング防御)などのガードレールを先に設定し、可能ならワーカー/隔離プロセスで実行するのが安全です。
まとめ
open():識別 + 低コスト情報確認段階(ピクセルはまだないかもしれない)verify():壊れたかの一次フィルタ(デコードなしで検査、以降使用するには再オープン)load():デコード/メモリ使用が始まる点(検証段階での乱用は禁物)- アップロード安全の実務回答:サーバーが再エンコードした結果のみを信頼(ただし制限/隔離必須)
関連記事: