外部画像を安全に扱う
広告配信システムを構築・運用していると、ユーザーが外部ドメインの画像(例:https://sample.com/image.jpg
)を登録し、それを広告素材として使いたいという要件が発生します。
しかし、外部ドメインの画像をそのまま<img src=...>
で読み込ませることは、セキュリティやプライバシーの観点から非常に危険です。本記事では、Facebookなど大手サービスが実践している安全な画像配信の設計パターンと、それをGo言語で実装する現実的な方法について、技術的に詳しく解説します。
なぜ外部画像をそのまま使ってはいけないのか?
主なリスク:
-
マルウェア・XSS
-
画像形式に偽装されたスクリプトや、不正なEXIF情報が仕込まれている場合があります。
-
-
トラッキング
-
外部画像を読み込むと、そのサーバにユーザーのIPアドレス、User-Agent、Refererが送信されます。
-
Cookieも同一ドメインであれば送られますが、ドメインが異なれば送られません。
-
-
コンテンツ差し替え
-
ユーザーが画像URLを登録した後に、画像の中身だけを差し替えることで、後から不適切な内容にすり替えられる可能性があります。
-
Facebookなどがやっていること
Facebook(Meta)は、外部画像を直接使うことはありません。すべての画像を一度自社のサーバーで検査・加工し、scontent-*.fbcdn.net
などの自社CDN経由で配信します。これは以下の理由によるものです:
-
セキュリティの確保(EXIF除去・MIMEチェック・再エンコード)
-
トラッキング制御(外部へのリクエストを防ぐ)
-
パフォーマンス最適化(CDNキャッシュ配信)
-
コンテンツ審査対応(広告画像審査のために内容を確定化)
自社で安全に外部画像を扱うには?
✅ 安全な構成案:
-
ユーザーが外部画像URLを登録(例:
https://sample.com/img.jpg
) -
登録時 or 表示時にプロキシサーバーで:
-
画像を一時取得(
GET
orHEAD
) -
MIMEチェック、magic bytesチェック
-
再エンコード(Goの
image.Decode()
+jpeg.Encode()
など) -
不正なEXIF・メタ情報を除去
-
-
再エンコード後の画像をそのままメモリで返却(ディスク保存なし)
-
ユーザーのブラウザには
yourdomain.com/proxy?url=...
の形式で自ドメイン配信
再エンコードとは?なぜ重要?
画像ファイルはピクセル情報だけでなく、EXIF情報やICCプロファイル、コメントセクションなどさまざまなメタデータを含みます。そこに悪意あるコードや個人情報が含まれるケースがあります。
再エンコードの利点:
-
不要なメタ情報を全削除
-
マルウェアやトラッキングを除去
-
常に標準フォーマット(JPEG/PNG)で再生成
img, _, _ := image.Decode(resp.Body) // 画像デコード
jpeg.Encode(w, img, &jpeg.Options{Quality: 85}) // 再エンコードしてレスポンス返却
差し替え検出はできるのか?
はい、外部画像の差し替えを検知する仕組みも可能です。
方法:
-
画像URL登録時に
Last-Modified
やETag
,Content-Length
を保存 -
表示時にHEADリクエストで再取得
-
値が一致していれば表示許可、一致しなければ拒否
保存せずに再エンコードだけするのは現実的か?
✅ 現実的で、多くの大手サービスも採用している方法です。
この構成の利点:
項目 | 内容 |
---|---|
セキュリティ | EXIF・不正MIME除去、XSS防止 |
プライバシー | 外部サーバへのIP/Cookie送信なし |
パフォーマンス | CDNキャッシュ活用可能(短期) |
シンプル性 | ストレージ管理が不要 |
注意すべきセキュリティ対策
-
SSRF防止(127.0.0.1やAWS内部メタデータへのアクセス制限)
-
サイズ制限(5MB上限など)
-
タイムアウト制限(5秒以内など)
-
MIMEとmagic bytesの整合確認(JPEGなら
FFD8FF
, PNGなら89504E47
) -
自サイトへの再帰的プロキシを禁止
まとめ
外部画像を広告素材として安全に使うには、「プロキシ経由で画像を再取得し、無害化処理をして自ドメインから配信する」構成が最も現実的かつ安全です。
Go言語を使えば、画像の取得・解析・再エンコード・配信まで非常に効率よく処理できます。ストレージ保存なしでもこの仕組みは十分実用的で、多くの商用サービスで実践されています。
ご希望があれば、実装例やコードスニペットの提供も可能です。
登録日:
更新日: