JWTをセッション管理に転用するのはあまり良いアイデアではない(認証だけならいいよ)

JWTをセッションに使うことに関して最近少し議論があったので、自分のお気持ちを表明したいと思います。

私は以前SPAを書く時にJWTをセッション管理に使おうとしたことがありましたが、仔細に検討していくとJWTをセッション管理に使うのは無意味にセキュリティ上のリスクを増やすだけで、伝統的なクッキーを使ったセッション管理を使った方が良いという結論に至りました。

前提を整理するためにあらかじめ前置きすると、「JWTをセッション管理に使う」というのは認証APIなどで返ってきたJWTをlocalstorageなどJavaScriptからアクセスできるストレージに保管しておいて、ajaxでサーバにリクエストを投げるたびにAuthenticationリクエストヘッダなどにJWTを付けて送る使い方を指します。

JWTをセッション管理に使うべきではないと思った理由の詳細は以下適当に箇条書きにします。

  • JWTをセッションに使うと、サーバー側でセッションストレージを持たなくても済むが、同じことはいわゆるクッキーセッション(クッキーにHMACで署名したデータを書き込んでセッションとする方法)でもできる
  • JWTをlocalstorageなどのJavaScriptからアクセスできるストレージに保管するのは、認証IDや署名されたトークンをhttpOnlyフラグを立てたクッキーに保管するよりもリスクが大きい
  • なぜならlocalstorageに認証トークンを保持すると、XSSがあった際に誰にも気づかれずに認証トークンを収集され続けたりセッションハイジャックされる恐れがある
  • XSSは無いに越したことはないが、だからといってXSSを経由したセッションハイジャック対策をしなくてもいい、ということにはならない
  • なぜなら、XSSは開発者のエスケープし忘れなどのポカミスによって引き起こされると認識されることがあるが、実際にはそれだけではなく、ブラウザやサーバー、言語処理系、ミドルウェアなどのバグによっても引き起こされる。最近の徳丸さんのブログに取り上げられた例では、PHPとApacheのバグを組み合わせて引き起こされるXSS(https://blog.tokumaru.org/2018/09/cve-2018-17082-cache-poisoning.html)が紹介されている。こういった事例を鑑みるに、XSSはアプリケーション開発者が気をつけてコードを書けば100%防げると断言することはできない
  • 一般的なウェブアプリケーションで、ユーザーが危険な処理をする際に、ログインしているユーザーに対して再度パスワード入力させるのは、セッションハイジャックされても致命的な被害を避けるためでもある。これと同様に、XSSがあったとしてもそれがセッションハイジャックにつながらないように対策をするのは変な話ではない。セキュリティ対策を0か1かで判断するのは明らかに間違っていると思う
  • クッキーセッションを用いると、JWTと同じようなステートレスなセッション管理ができる。クッキーにhttpOnlyフラグを付けることで、XSSがあっても認証トークンを収集されてセッションハイジャックされるというようなシナリオは防ぐことができる
  • よくよく考えるとセッションストレージを持たない完全にステートレスなセッション管理は、一般的なアプリケーション開発の要件上それほど嬉しくない。ユーザがパスワード変更する際にそのユーザのセッションを強制ログアウトさせるというよくあるユースケースを考えると、完全にステートレスなセッション管理では要件を満たすことができない。これはクッキーセッションでも同様
  • JWTでこの要件を満たすためには、JWTのjtiクレームにユニークなトークンを設定してサーバー側で失効させるjtiクレームのトークンを覚えておく必要があるだろう。結局これはサーバー側でセッションストレージのようなものを持たないといけないことになる
  • セキュリティ上のリスクが増える割には得られるものは不完全にステートレスなセッションで、しかも同じことはよりリスクを減らせるクッキーセッションでも可能である
  • こうやって見ていくと、JWTをセッション管理に転用するのは無意味にセキュリティ上のリスクを増やしているだけのようにしか見えない

普通のセッション、クッキーセッション、JWTによるセッションというこれらの選択肢を見てみると、セキュリティ上一番割に合わない選択肢がJWTを使ったセッション管理で、わざわざこれを選択するのはよっぽど何か特殊な要件があったりする場合かなあという感じになりました。こちらからは以上です。