きっかけ
昨年(2021年9月ごろ)に徳丸さんのこのツイートを見て、「2022年にはJWTを用いたセッション管理に代表される、ステートレスなセッション管理は世の中に受け入れられなくなっていくのだろうか?」と思っていました。
OWASP Top 10 2021 A1に「JWT tokens should be invalidated on the server after logout.」(私訳:JWTトークンはログアウト後にサーバー上で無効化すべきです)と書いてあるけど、どうやって無効化するんだ? ブラックリストに入れる?https://t.co/bcdldF82Bw
— 徳丸 浩 (@ockeghem) 2021年9月10日
JWT大好きな皆さん、ここはウォッチしないとだめですよ。これがそのまま通ったら、ログアウト機能でJWTの即時無効化をしていないサイトは脆弱性診断で「OWASP Top 10 2021違反」と報告されてしまいますyo ! https://t.co/ltLb3Fd8mV
— 徳丸 浩 (@ockeghem) 2021年9月10日
結論
冒頭だけ読んで勘違いが広まるとよくないので、議論の結果最新版では方針が変わったということだけ先に書いておきます。詳細が気になる方は最後まで読んでみてください🙇♂️
現状(2022年3月)の日本語版の記述
OWASP Top10 2022の「A01:2021 – アクセス制御の不備」の日本語版では、2022年3月3日時点では以下のように書かれています。
JWTトークンはログアウト後にはサーバー上で無効とされるべきである。
この記述からは、ログアウト時にクライアントサイドでセッション(JWT)を捨てるだけでは不十分で、クライアント側がJWTを再利用すればサーバへのアクセスが成功してしまうのが問題であるということが読み取れます。 サーバ側で無効なJWTを管理しなければならないということは、JWTを利用したセッション管理に代表されるようなステートレスなセッション管理は認証の実装方法として不十分なのでしょうか?
議論
こちらのIssueで議論がされていました。(徳丸さんのツイートよりも後に行われた議論のようです)
議論の詳細はここでは書きませんが、ここの議論からわかることをまとめます。
まず、JWT仕様を見る限り、OAuthをベースとしたOpenID Connectで使用することが想定された設計であることは明らかです。
OAuthには2つのトークンがあり、短命なアクセストークンと長命なリフレッシュトークンから構成されています。 それぞれのトークンがどんな形式であるべきかは指定されていませんが、アクセストークンにはJWTが使われている実装が多いようです。
アクセストークンの生存期間を短命にすることで、アクセストークンが不正に利用されるリスクを低減しています(リスクを低減しているのであって、完全に防いでいるわけではない)。この短命なトークンの実装としてJWTを使うことで、ステートレスな認証を実装することができ、データベースの負荷低減に寄与します。
その代わりにリフレッシュトークンはサーバサイドでの管理を必須とし、ユーザがログアウトするなどの操作を行うとリフレッシュトークンが即時無効化され、アクセストークンの更新はできなくなります。
この前提があるため、少なくとも長命なアクセストークンを生成することは許容されなさそうです。どれくらいの時間が短命なのかどうかはサービスごとのリスク許容度によって判断する形になりそうですね。
(追記ここから 2022/04/18) 徳丸さんから反応をいただいたのですが、
たしかに誤解が広がるとよくないので、こちらでも強調しておきます。 JWTは本来的にはセッション管理のためのものではなく認証情報の受け渡しのためのものですが、その便利な特性からセッション管理にも転用されることもあるという背景があります。記事読みました。特にツッコミという程ではないですが、OIDC由来のJWTが元々「認証情報の受け渡し」を意図して設計されたものでありセッション管理を意図していたわけではないという点を強調しておきたいと思います。そうでないと、OIDCではこうだから…という議論の根拠が不明確になります。
— 徳丸 浩 (@ockeghem) 2022年4月18日
こちらも参考になったので紹介しておきます 🙇♂️
(追記ここまで)徳丸さんの指摘を受けての追記のあたりで、著者の認識はしっかりしていそうなので、"認証情報の受け渡しのため" のIDTokenについての記載、OAuthのリフレッシュ/アクセストークンとは要件が異なると言うところまで記載されていると読み手が理解しやすいかもしれないですね。
— 👹秋田の猫🐱 (@ritou) 2022年4月18日
「数分であろうと即時無効化されているべきであるセッションが有効なものとして使えるのはリスクは低減されているが問題であることに変わりはないのでは?」という意見ももちろんありますが、絶対に許容されないという温度感ではないようです。
その代わりに、この特性が一般にはまだ広く理解が広まっていないのでは?という懸念への対応として、以下のリンクを紹介することでメリットとデメリットを正しく理解してもらおう、ということで着地したようです。 www.oauth.com
変更
この議論の結果、2021年9月24日にはA01の記述を修正するプルリクエストが出おり、即日取り込まれていたのでした。
Stateful session identifiers should be invalidated on the server after logout. Stateless JWT tokens should rather be short-lived so that the window of opportunity for an attacker is minimized. For longer lived JWTs it's highy recommended to follow the OAUTH standards to revoke access.
ということで、
「ステートフルなセッション識別子は、ログアウト後にはサーバー上で無効とされるべきである。ステートレスなJWTトークンは、攻撃者の機会を最小にするために、むしろ短命であるべきである。寿命の長いJWTの場合は、アクセスを取り消すためにOAuth標準に従うことが強く推奨される。」
という内容に記述が変わりました。
日本語版が追いついていない😱
日本語版の記述はどうなっているかというと、この議論の結果が反映されておらず、英語版と日本語版で乖離が出ていることがわかりました。 日本語版だけを読んで勘違いが広がってしまうのもよくないので、英語版の最新に追従するプルリクエストを出してみました。問題がなければ取り込んでもらえるかな?と思っています。
JWTの取り扱いに関する記述が意味的な差分としては一番大きそうですが、他の差分に関しては軽微な修正だと思われます。