エムスリーテックブログ

エムスリー(m3)のエンジニア・開発メンバーによる技術ブログです

アンケート回答画面SPAにJWTを組み込んだ例の紹介

エムスリー エンジニアリングGの岩本です。

現在私の所属しているチームでは、以前作成したアンケートを作るためのシステムのサーバサイドリプレースを行っています。 4ヶ月ほど前にテックブログで書いたもののセッション管理部分について今回は記載します。 www.m3tech.blog

登場するシステムの紹介

f:id:cpw:20200728202730p:plain:w100

Dolphin。ここで紹介する以外にもエムスリーにはアンケートシステムがいくつかありますが、その流入ポイントとなるシステム。 エントリポイントにアクセスすると各システムにリダイレクトします。認証情報はこのシステムが持っています。

f:id:cpw:20200728202737p:plain:w100

BengalTiger。今回リプレースするSPAで作られたアンケート回答画面。Kotlin + Quarkus + Domaを利用して作られています。 将来的にグループ会社でも使いたいのでM3のシステムとはなるべく疎に作りたいと考えています。 詳細はアンケート作成システムのサーバサイドをKotlin + Quarkus + Doma, CQRSで構築している話 - エムスリーテックブログを参照してください。

課題

旧システムではセッションをメモリ上で管理しています。そのため、リリース時にセッションが切れてしまう良くない設計となっていました。 ただし、セッションがない場合には裏で弊社の認証基盤に毎回アクセスしてセッションを作り直すため、 ユーザが再度認証を求められるわけでは有りません。

今回リプレースするにあたってもリリース時にもセッションが切れない仕組みを構築したいのですが、M3の認証基盤とは接続しない方針です。今までの方法ではセッションを復元することができません。

改善案

取れる選択肢としては下記の3択です。

  1. Redisにセッション情報を格納する
  2. Cookieセッションにする
  3. 回答画面だけで有効なJWTを発行する

1はコストの面と障害点の増加という点から避けたいです。 2,3に関してはコストも障害点も増えないので1に比べるとベターです。

また、2と3を比較するとアンケートの回答画面(SPA)で使える認証情報がほしいのであってページをまたいでの セッション情報は不要ということから、3のJWTを利用することにしました。

認証の仕組み

f:id:cpw:20200728161810p:plain

  • 1で認証情報を持っているDolphinの回答開始URLにユーザがアクセスします
  • 2でJWT Aを発行します。このJWTには下記の情報を格納します。
    • ユーザの認証情報
    • アンケートIDなどの使い回しを防ぐための情報
    • 有効期限はURLを使いまわしできないように数秒程度
  • 4でJWT Aをクエリに格納しBengalTigerへリクエストします
  • 5でJWT Aを検証
  • 6でBengalTigerでJWT Bを発行します。JWT AとJWT Bを分けることでリダイレクトURLを使いまわしできないようにしています
  • 7でJWT BをHTMLに埋め込んだSPAを返却
  • 以降はJWT BをリクエストのたびHTTPヘッダーに仕込むことで認証情報を引き回します

JWTの懸念点

一般的にJWTをセッション相当として使う場合の懸念点に関しても考慮しています。

  • トークンのrevokeができない
    • JWT Aはリダイレクト時にだけ利用され十分に短時間の有効期限を持つので使い回しができない
    • JWT BはアンケートID専用なので他の機能には影響がでない
  • 情報がユーザに見えてしまう
    • 格納する情報はユーザIDとアンケートIDだけなので見えても問題ない
  • キーが推測される
    • algクレームを固定することで改ざんを防ぐ

まとめ

  • アクセスされたURLだけで有効な認証情報を持ったSPAを実現できました。
  • Redisも不要となったのでコストと障害点を減らすことができました。

We're hiring!

エムスリーではKotlinでサーバサイド開発をしたいエンジニアを募集しています。 社員とカジュアルにお話することもできますので、興味を持たれた方は下記よりお問い合わせください。

open.talentio.com

jobs.m3.com