🔐 外部画像を安全にプロキシ経由で表示し、改ざんも検出する方法【Go言語+Base64活用】
Webサービスでユーザーが外部の画像URLを登録できるようにしている場合、意図しない改ざんやマルウェアの混入リスクが常に存在します。
この記事では以下を解説します:
-
✅ 外部画像のプロキシ表示とセキュリティ担保の方法
-
✅ 再エンコードによるEXIF・マルウェア除去
-
✅ 画像そのものを保存せずに改ざんを検出する方法
Go言語を用いた実装例と共に、画像保存なしでセキュリティを担保するアプローチをご紹介します。
🔥 なぜ画像のプロキシ表示が必要か?
ユーザーが登録する画像URLが自分の管理外のドメイン(例: https://sample.com/image.jpg
)だった場合、以下のようなセキュリティリスクがあります。
リスク | 内容 |
---|---|
☠️ マルウェアの埋め込み | EXIFやファイル構造を悪用した攻撃 |
🕵️ トラッキング目的の画像 | Cookie送信やIP取得のリスク |
🎭 登録後に画像を差し替える | 表面上は同じURLでも別画像にすり替えられる |
✅ ステップ1:安全なプロキシ構成
最初のステップとして、自前のサーバーを介して外部画像を表示する構成を取ります。
ユーザー → 自サーバー(画像プロキシ)→ 外部画像URL
🎯 なぜプロキシを通すのか?
-
自ドメイン上で画像を扱うことでCookie漏洩防止
-
ウイルススキャン、MIME検証、EXIF除去が可能
-
外部ドメインからのトラッキング防止
🧼 ステップ2:Goで画像検証+再エンコード
以下のような処理で安全化します:
-
Content-Type
(MIME)確認 -
image.Decode()
でファイルの形式・構造検証 -
再エンコード(JPEGやPNGとして)してEXIF含むメタデータを除去
-
その結果の画像を返却(または保存)
// 画像の読み込み・再エンコード(安全化)
img, _, err := image.Decode(bytes.NewReader(data))
var buf bytes.Buffer
err = jpeg.Encode(&buf, img, nil) // 再エンコードでEXIF等除去
この処理を行うことで、悪意あるEXIF情報や不可視のペイロードを除去し、安全に配信可能になります。
🔍 ステップ3:改ざんチェック(保存しない構成で)
💡 アイデア:Base64文字列にして先頭・末尾を保存
画像本体は保存せず、Base64化した文字列の一部のみ(先頭・末尾)を保存します。
base64Str := base64.StdEncoding.EncodeToString(buf.Bytes())
pre := base64Str[:500]
tail := base64Str[len(base64Str)-500:]
これをDBに保存:
ad.PathBannerPre = pre
ad.PathBannerTail = tail
🔁 次回以降の比較:
-
同じ画像URLから再取得
-
再エンコード後のBase64文字列のpre/tailとDBに保存された値を比較
-
一致しなければ画像が変更されたと判断
🧠 拡張アイデア:画像の四隅部分だけでチェック
全体の先頭・末尾以外に、画像の左上・右上・左下・右下などの特定ピクセルエリアだけをBase64化して比較するという高度な実装も可能です。
-
一部だけ変更された場合にも差分が出やすい
-
広告やバナーでよくある「小さなロゴ差し替え」にも有効
💾 サーバー保存 vs プロキシ型:どちらがコスト高?
方法 | 特徴 | ディスクコスト | CPUコスト | 安全性 |
---|---|---|---|---|
🔁 プロキシ+毎回再エンコード | 保存しない | 低 | 高(都度処理) | 高 |
💾 サーバー保存+初回検査 | ローカル配信 | 高 | 低 | 高 |
-
小規模・低トラフィック(数千ユーザー)であれば保存の方が現実的
-
非保存構成でも、Base64チェックで差し替え検出が可能
🎯 実運用構成イメージ
-
登録時に画像をプロキシ取得
-
MIME / EXIF チェック & 再エンコード
-
Base64 変換 →
pre
/tail
をDB保存 -
表示時にはプロキシ経由で再取得 or キャッシュ活用
-
一定期間ごとに再チェック可能
📝 まとめ
項目 | 内容 |
---|---|
セキュリティ | EXIF除去・トラッキング防止・差し替え検出 |
保存構成 | 少人数ならローカル保存が現実的 |
非保存構成 | Base64比較で改ざん検出できる |
Go実装 | image.Decode , jpeg.Encode , base64.EncodeToString を使用 |
📢 最後に
この手法は、広告画像やユーザーアップロード画像を扱う全てのサービスに活用できます。
特に「画像は保存したくないけど、安全性は担保したい」サービスには理想的な構成です。
ご希望があれば、この仕組みをOSS化したサンプルリポジトリやAPIモックも公開可能です。
Zenn、Qiita、GitHubでの共有も検討中ですので、ご要望があればお知らせください!
必要に応じて、記事タイトルや構成をZenn・Qiita向けに調整した構成にもできますので、お気軽にご相談ください。
登録日:
更新日: