kawasin73のブログ

技術記事とかいろんなことをかくブログです

JWT はユーザに渡すな

JWT とかいてジョットと詠む。どうも、かわしんです。タイトルは釣りです。

この記事は、JWT はログアウトが大変 という内容です。以下で挙げるデメリットを許容できるなら JWT をユーザに渡してもいいと思います。

ログアウトとは、管理者による強制ログアウトや、ユーザのパスワードの変更による全トークンの無効化をさします。ログアウトによって全てまたは一部のトークンが無効化されるユースケースです。

JWT におけるログアウト

JWT はログアウトが大変です。なんかいい方法がないものかと調べていましたが、以下の記事に落ち着きました。

javascript - Invalidating JSON Web Tokens - Stack Overflow

この記事の結論としては、いい方法などない というものです。残念でした。

JWT をログアウトに対応させる方法は ブラックリストを用意するトークンの有効期限を短くする の 2 つだけです。

NOTE : ここではマイクロサービスのことが念頭にあります。

ブラックリスト方式

ブラックリストを用意する方法では、無効化されたトークンをブラックリストに保存します。

ブラックリストトークンは、そのトークンの一番最後の有効期限まで保存し続けます。そのあとは TTL なりで削除しても大丈夫です。

そして、各サービスは JWT の検証の際にブラックリストにアクセスして JWT が無効化されていないかをチェックします。

これでは、JWT のメリットであるトークンの検証の分散・独立・ステートレス性が失われてしまいます。

一方で、ブラックリストに保存するのは無効化されたトークンだけなので、ブラックリストのストレージサイズは全てのトークンを中央に保存するよりは小さくなります。検索も速くなるでしょう。

有効期限を短く設定する方式

トークンの有効期限を短く設定し、頻繁に JWT の更新をさせることで、JWT の更新時に無効化されたトークンの更新を弾く方法です。

JWT のメリットであるトークンの検証の分散・独立・ステートレス性は保たれます。

一方で有効期限を短くすることでどの程度短くするかによりますが、トークンの更新リクエストが頻繁に発生することになります。

また、最大のデメリットとして 即時無効化ができない という重大な欠点があります。セキュリティ的にまずいです。多分 JWT を使ってるサービスはこれを許容してるんだと思いますが、実装を手抜きするために仕様を捻じ曲げてセキュリティ的なデメリットを容認してしまうのは個人的にはしたくないです。

マイクロサービスにおける JWT

さて、マイクロサービスにおける認証を調べているとクライアントからのアクセストークンを API Gateway で内部のトークンに変換する方法がしばしば紹介されています。(Microservices Authentication and Authorization Solutionsマイクロサービスシステムにおける認証ストラテジ など)

最初はなんでこんな複雑なことをするんだと思っていたのですが、JWT のログアウトの問題を調べているうちに納得しました。

内部のトークンが JWT の場合、Gateway で利用する変換テーブルからアクセストークンを削除すれば JWT はなくなり使われなくなってしまうので、即時ログアウトが実現できます。

JWT は Gateway 内部のプライベートなネットワークの中でのみ利用されるため JWT 自体はログアウトのことを考える必要がありません。

Gateway の中でアクセストークンの変換が高速にできるのかよという疑問はありますが、そこはクラウドプロバイダーの謎テクノロジーが解決しているのでしょう。

マイクロサービスの文脈では複数のサービスを利用することやサービスが別のサービスに連鎖的にリクエストすることがありえます。各サービスが中央の認証テーブルにアクセスするコストが JWT を使うことにより削減されます。これは連携するサービスの数が多いほどこの効果は大きくなるはずです。

JWT をユーザに渡さず、プライベートネットワークの内部だけで使うという方法は一般的なユースケースに適っていて、いい JWT の使い方だと思います。Gateway 周りの実装がじょっとめんどくさそうですが。