Edited at

アップロードしたファイルの完全性を検証する

More than 1 year has passed since last update.

mixiグループ Advent Calendar 2016の12日目の記事です。

ユーザから写真をアップロードしてもらう機会が多いのですが、やはり携帯回線からのアップロードしたファイルは壊れているケースが多く、ファイルの完全性をチェックしたいなぁと考えておりました。

じゃあどうやって完全性を検証しようかと調べていたところ、Content-MD5ヘッダーにたどり着きました。


Content-MD5ヘッダーって?

まず先にお断りしておきますが、2016年12月現在のHTTP/1.1では定義されていないヘッダーです。

もともとContent-MD5ヘッダーは、MIMEでメールの本文の完全性を保証するために定義されていました(RFC 1864)。

それをHTTPに持ってきたのがRFC 2616です。しかし、2014年のHTTP/1.1の改定(RFC 7230, RFC 7231, RFC 7232, RFC 7233, RFC 7234, RFC 7235)で廃止されています。

実際どんなものなのかというと、まぁ名前そのままの通りで、bodyのMD5ダイジェストをbase64でエンコードしたものをContent-MD5ヘッダーとして付与するというものです。


完全性の検証

どうやって完全性を検証するのかという話は単純で、クライアント・サーバ側でそれぞれファイルのMD5を計算して一致するか検証するだけです。

そのMD5の受け渡しに、Content-MD5ヘッダーを使おうというのが今回のお話です。

まずクライアント側でファイルのMD5を計算しておき、それをContent-MD5としてリクエストヘッダーに追加してファイルをサーバにアップロードします。

サーバ側では、受け取ったファイルのMD5とリクエストヘッダーのContent-MD5が一致するか検証し、適切なレスポンスを返してあげます。


AWS S3

S3ではこのヘッダーを使っていい感じにアップロードされたファイルの完全性チェックをしてくれます。

アップロード時にContent-MD5をヘッダーをつけることで、S3側が勝手にアップロード後のファイルのMD5と比較してくれて一致しないと400エラーを返してくれるようです。

参考: Amazon S3へアップロードされたファイルの完全性の検証


番外編 ETagを利用する

弊社ではmBaaSとしてFacebookのparse.comを利用していた(現在はGCPへの移行中です)ので、ファイルアップロード時の完全性チェックを挟むことができませんでした。

そのため、parse.comへアップロードしたファイルのETagがファイルのMD5だということを利用してクライアント側だけで完結するような方法をとっております。

具体的には、アップロード前にあらかじめファイルのMD5を計算しておき、ファイルアップロード後にHTTPヘッダーのみを取得し、ETagとあらかじめ計算しておいたMD5が一致するか検証するというちょっと泥臭い方法です。


AWS S3のETag

S3のオブジェクトのETagは基本的にはMD5になります。

parse.comのファイルホスティングにもS3が使われているので、上記のようなことができるわけです。

しかし、S3へ分割アップロードをした場合は、MD5ではないものがETagに設定されるので注意が必要です。