自前のアップローダーで起きる問題
開発者 ――
インフルエンサーとファンをつなぐコミュニティサイト「Qitter」を作ったぞ!
テキストと画像をPOSTするだけのシステムだから、全部自前の実装で作っちゃったぞ。
投稿者 ――
今日もQitterに投稿しなくちゃ!
「晩ご飯なう!」
閲覧者 ――
「推しちゃんの投稿キター!」
「推しちゃんの投稿した画像は全部保存しちゃうぞ!」
「ん…?」
「撮影場所…、つまりこれは推しちゃんの住所では!?」
「………」
そして炎上へ ――
何故このようなことが起きるのか
画像には、画像自体のデータ以外にも、テキスト情報を保持できる仕組みがあります。
有名なものだと、jpg形式におけるEXIF情報です。
スマートフォンで撮影すると、位置情報(緯度経度)がEXIF情報に付与されたり、
一眼レフで撮影すると、カメラのメーカーや撮影時の設定がEXIF情報に付与されたり
Photoshopで加工して保存すると、ソフトの名称とバージョンがEXIF情報に付与されたり、
さまざまな情報がいつの間にかこの領域に保存されています。
冒頭の例では、撮影時の緯度経度が付与された写真がアップロードされ、そのままWeb上で配信されてしまいました。
どのように対策するべきか
画像データからEXIF情報部分を削除することが可能です。
冒頭の例のような事故が起こりうるWebサービスにおいては、画像アップロード時にシステム側でEXIF情報を削除するような処理を実装する必要があります。
ちなみに、iPhoneでは画像アップロード時に緯度経度部分を自動で削除してくれる仕様があったりと、ユーザー側にも情報流出を防止する仕組みがあるようです。
EXIF情報の削除方法
画像アップロード機能を実装する際、画像処理ライブラリを用いて、リサイズや圧縮をする場合も多いと思います。
そのように何かしらの加工を挟んでから保存している場合は、その工程の中で既にEXIF情報が削除されている場合があります。
そうでなかった場合、画像処理ライブラリを使ってEXIF情報を明示的に削除しましょう。
有名どころでは「ImageMagick」というソフトウェアがあり、多くのサーバーサイド言語では、このソフトウェアをプログラムから操作するためのライブラリが存在します。
実装例(ImageMagick + PHP)
$imagick = new Imagick('input.jpg'); // 読み込み
$imagick->stripImage(); // EXIF情報等のデータを削除
$imagick->writeImage('output.jpg'); // 保存
$imagick->destroy();
pngだからって安心できない!
EXIFってjpgとかだけでしょ?という認識はちょっと危険かもしれません。
pngには、補助チャンクという保存領域が用意されています。
jpg形式の画像をpngに変換した際に、ご丁寧にEXIF情報をこのpngの補助チャンクに転記してくれる場合があるそうです。
さらに、2017年に追加されたpngの仕様にて、EXIF用のチャンク領域が追加されたようです。
そのため、「pngに変換して保存してるから大丈夫」とは言い切れないため、
pngを用いるケースでも情報が削除されているか確認したほうがよさそうです。
おわりに
この問題って結構危ないことになりかねない割に、普通にプログラミングを勉強しているだけだと習う機会がない気がします。
少しでも周知につながれば幸いです。