asoview! TECH BLOG

アソビュー株式会社のテックブログ

購入フローでセキュアにファイルアップロードしたい

f:id:knt_mr:20220403180530j:plain

アソビュー! Advent Calendar 2021 の8日目です。 エンジニアの村松です。

アソビューでは、一部施設において「年間パスポート」や「シーズン券」の販売を開始しました。これらは、他の Web チケット購入と異なり、購入フローの中で「顔写真」を登録できる機能があります。

f:id:knt_mr:20220403180608p:plain

エンドユーザーが登録する顔写真は、個人情報と同じようにセキュアに取り扱う必要があります。今回はこのあたりについて書きます。

まず、やりたいことをざっくり挙げるとこちら。

  1. 購入フローで顔写真を登録する
  2. 顔写真を購入データと紐付けて保存する
  3. 管理画面から顔写真を参照&ダウンロードする

あとは、これらをいかにセキュアに実現するかという観点で方式を検討しました。

先にそれぞれのフローを記載します。説明は後述します。

f:id:knt_mr:20220403180658p:plain
1. 購入フローで顔写真を登録する

f:id:knt_mr:20220403180724p:plain
2. 顔写真を購入データと紐付けて保存する

f:id:knt_mr:20220403180741p:plain
3. 管理画面から顔写真を参照&ダウンロードする

Amazon S3 + AWS Key Management Service

アソビューのサービスの大部分は AWS を利用しており、購入フローで登録した顔写真は Amazon S3 にアップロードしています。

S3 は、デフォルトでパブリックアクセスをブロックしますが、顔写真をよりセキュアに管理するため、クライアントアプリケーション側で暗号化 (client-side encryption) してからアップロードしています。暗号化には、AWS Key Management Service のキーを使用しています。

クライアントアプリケーション側で暗号化してから S3 にアップロードするため、例えば、AWS マネジメントコンソールからファイルをダウンロードしても、ファイルの中身を見ることはできません。なお、データベースには、アップロードした S3 のオブジェクトキーのみを購入データと紐付けて保存しています。社内外からのアクセスに対して不必要に顔写真を閲覧できないようにしています

S3 上に保存されている暗号化したファイルは、クライアントアプリケーションで S3 からダウンロードするタイミングで復号されます。管理画面を表示する際は、復号したデータを Base64 にエンコードしてフロントエンドに返却し、デコードして表示しています。管理画面上のダウンロード機能はフロントエンド側で実装しています。

当初、Base64 ではなく、URL ベースでフロントエンドに返却して顔写真を表示しようと思っており、Amazon S3 が提供する 署名付き URL あたりを調査したのですが、署名付きとは言っても URL が外部に漏れてしまうと一時的でも第三者に閲覧される可能性があるため、採用は見送りました。

One more thing…

購入フローで顔写真を登録するにあたり、もうひとつ考慮することがあります。

それは、エンドユーザーが顔写真を登録したものの、購入はせずに途中で離脱するケースです。この場合、S3 上に購入データに紐付かない無駄なファイルが残ってしまいます。

このケースの対策として、まず、2段階でアップロードする方式を採っています。最初に、購入フローで登録した顔写真を一時フォルダにアップロードします。次に、エンドユーザーが購入を確定したタイミングで一時フォルダから正のフォルダにファイルを移動します。(当然ですが、暗号化したファイルを移動しても暗号化は維持されます)

そして、一時フォルダのファイルに対して Amazon S3 の ライフサイクルルール を適用し、一定期間が過ぎたファイルは自動的に削除されるようにします。これによって、購入データに紐付かない不要なファイルが S3 上に残ることは回避できるようになりました。

まとめ

これらの取り組みによって、冒頭に挙げたやりたいことをセキュアに実現できました。同様の事例を検討している方の参考になれば幸いです。

One more more thing…

アソビューでは「生きるに、遊びを。」をミッションに、一緒に働くメンバーを募集しています!ご興味がありましたらお気軽にご応募いただければと思います!

www.wantedly.com