JA EN

画像ファイルのセキュリティ脆弱性 - アップロード検証とサーバーサイド防御の実践

· 約 9 分で読めます

画像アップロードに潜むセキュリティリスクの全体像

画像アップロード機能は Web アプリケーションで最も一般的な機能の 1 つですが、同時に最も攻撃されやすい入口でもあります。攻撃者は画像ファイルを装った悪意のあるファイルをアップロードし、サーバーサイドでのコード実行、XSS (クロスサイトスクリプティング)、DoS (サービス拒否) などの攻撃を試みます。

主要な攻撃ベクトル:

防御の基本原則は「クライアントからの入力を一切信頼しない」です。ファイル名、拡張子、Content-Type ヘッダー、ファイルサイズ、画像の内容すべてを検証し、安全が確認されたもののみを受け入れます。

マジックバイト検証 - ファイルの真の形式を判定する

マジックバイト (ファイルシグネチャ) は、ファイルの先頭数バイトに含まれる固定のバイト列で、ファイルの真の形式を識別します。拡張子や Content-Type は容易に偽装できますが、マジックバイトの検証により実際のファイル形式を確認できます。

主要画像フォーマットのマジックバイト:

Node.js での実装例:

const fileTypeFromBuffer = require('file-type'); async function validateImage(buffer) { const type = await fileTypeFromBuffer(buffer); const allowedTypes = ['image/jpeg', 'image/png', 'image/webp', 'image/gif']; if (!type || !allowedTypes.includes(type.mime)) { throw new Error('Invalid image format'); } return type; }

マジックバイト検証だけでは不十分な理由:

そのため、マジックバイト検証は防御の第一層として使用し、追加の検証 (画像の再エンコード、メタデータ除去) と組み合わせる必要があります。

画像の再エンコード - 最も効果的な防御手法

アップロードされた画像を一度デコードし、新しい画像として再エンコードすることは、最も効果的なセキュリティ対策です。この処理により、画像データ以外のすべてのペイロード (埋め込みスクリプト、ポリグロット構造、悪意のあるメタデータ) が除去されます。

再エンコードの実装 (Sharp / Node.js):

const sharp = require('sharp'); async function sanitizeImage(inputBuffer) { const metadata = await sharp(inputBuffer).metadata(); if (metadata.width > 10000 || metadata.height > 10000) { throw new Error('Image dimensions too large'); } if (metadata.width * metadata.height > 100000000) { throw new Error('Total pixel count exceeds limit'); } return sharp(inputBuffer).resize({ width: Math.min(metadata.width, 4096), height: Math.min(metadata.height, 4096), fit: 'inside', withoutEnlargement: true }).removeAlpha().jpeg({ quality: 85, mozjpeg: true }).toBuffer(); }

再エンコードで除去されるもの:

注意点:

SVG のサニタイズ - XSS 攻撃の温床への対策

SVG は XML ベースのベクター画像フォーマットですが、<script> タグ、イベントハンドラ (onload, onerror)、外部リソース参照 (<use href>, <image href>) を含むことができるため、XSS 攻撃の温床になります。SVG のアップロードを許可する場合は、厳格なサニタイズが必須です。

SVG に埋め込み可能な攻撃コード例:

SVG サニタイズの実装:

const { JSDOM } = require('jsdom'); const DOMPurify = require('dompurify'); function sanitizeSvg(svgString) { const window = new JSDOM('').window; const purify = DOMPurify(window); return purify.sanitize(svgString, { USE_PROFILES: { svg: true }, ADD_TAGS: ['use'], FORBID_TAGS: ['script', 'foreignObject'], FORBID_ATTR: ['onload', 'onerror', 'onclick', 'onmouseover'] }); }

より安全なアプローチ:

ImageTragick と画像処理ライブラリの脆弱性対策

ImageTragick (CVE-2016-3714) は ImageMagick の重大な脆弱性で、特殊な画像ファイルを処理させることでリモートコード実行 (RCE) が可能でした。この脆弱性は画像処理ライブラリの危険性を世界に知らしめ、画像処理のセキュリティ設計に大きな影響を与えました。

ImageTragick の攻撃手法:

対策:

その他の画像処理ライブラリの脆弱性:

防御の多層化: 単一の対策に依存せず、マジックバイト検証 → サイズ制限 → 再エンコード → メタデータ除去 → サンドボックス実行の多層防御を構築してください。

実装チェックリスト - 安全な画像アップロードの設計

画像アップロード機能を実装する際のセキュリティチェックリストです。すべての項目を満たすことで、既知の攻撃ベクトルに対する包括的な防御を実現します。

フロントエンド (クライアントサイド):

サーバーサイド (必須):

配信時:

関連記事

画像共有時のプライバシー対策 - メタデータ削除から顔ぼかしまで

SNS やメッセージアプリで画像を共有する際のプライバシーリスクと、EXIF 削除、位置情報除去、顔ぼかしなどの具体的な対策を解説します。

EXIF データとプライバシーリスク - 位置情報漏洩を防ぐ方法

写真に埋め込まれる EXIF データの種類とプライバシーリスクを解説。GPS 位置情報の漏洩事例と、安全に写真を共有するための EXIF 削除方法を紹介します。

画像フォーマットの自動判定技術 - マジックナンバーによるファイル識別の仕組み

画像ファイルのフォーマットを拡張子に頼らず正確に判定する技術を解説。マジックナンバー、MIME タイプ推定、バイナリヘッダー解析の実装方法を具体的なコード例とともに紹介します。

写真ワークフロー自動化 - スクリプトで大量画像を効率処理する方法

数百〜数万枚の写真を効率的に処理するワークフロー自動化を解説。ImageMagick、sharp、ExifTool を使ったバッチ処理の実践テクニックを紹介します。

大量画像の一括処理ワークフロー - 効率的なバッチ処理の設計と実装

数百〜数千枚の画像を効率的に一括処理するワークフローの設計方法を、コマンドラインツールとスクリプトの実例で解説します。

favicon の作り方完全ガイド - ICO, SVG, PNG の使い分け

favicon の仕組みから、ICO, SVG, PNG 各フォーマットの特徴、ダークモード対応、各ブラウザの対応状況まで実践的に解説します。

関連用語