Persistence

続けることに意味がある。

ブラウザから直接S3にファイルをアップロードする方法

ブラウザからS3にファイルをアップロードする場合、S3のアクセスキーやシークレットキーを隠ぺいするためにブラウザ→サーバ→S3というようにサーバを経由してアップロードする事を考えますが、サーバを経由せずに直接S3にアップロードする方法がありました。

元の情報はこのページです。

devcenter.heroku.com

概要

何が行われているかというと、

  • ブラウザがサーバに対してS3のシグネチャ付きのURLを要求します。
  • サーバはS3に対してSDKシグネチャ付きのURLを要求します。
  • サーバはブラウザにS3から返されたシグネチャ付きのURLを返します。
  • ブラウザはアップロードしたいファイルを受け取ったURLにPUTします。

シグネチャ付きのURLにはアクセスキーが含まれますがシークレットキーは含まれないので、一応安全ではあります(ただあまり見せたくはないですが)。またこの方法をを取ることで、通信は2往復になりますがブラウザからサーバへファイルを送る必要がないので通信量・通信時間は少なくなります。

注意点

1つは情報元のページにもありますが、S3の『CORSの設定』で送信元Origin(ドメイン)からのPUTを許可しておくということです。この設定がない場合、403エラーで"No 'Access-Control-Allow-Origin' header is present on the requested resource."が返されます。

もう1つは、情報元のページに無いのですが、aws-sdkのconfig設定にregionとsignatureVersionの設定が必要でした。この設定がない場合は、403エラーで"SignatureDoesNotMatch"が返されます。一応PRを送ってGitHubのソースにはmergeされています。(と書いた後にもう一度再現させてみようと思ってsignatureVersionの設定を削除してリクエストしたらエラーにならずにできました。謎です。)

問題点

1つはやはり上にも書きましたが、アクセスキーが見えてしまうということです。アクセスキーとシークレットキーがセットでないと何もできないですが、重要なシステムではオススメできません。

もう一つは、ファイルに何か加工(例えば画像をリサイズするなど)したい場合、S3にアップロードした後で行うことになります。システムによってはアップロード後に非同期で加工でも問題ないかもしれませんが、DollFaceDetectorの場合はアップロード後すぐにAPIにファイルのURLを渡すので、先にリサイズなどの加工をする必要がありました。