(※この記事は 別媒体に投稿した記事 のバックアップです。 canonical も設定しています)
2021-03-28
※この記事は別アカウント(hyiromori)から引っ越しました
OpenID Connect で出てくる JWT について調べた結果をまとめてみました。
ざっくりいうと、JSON形式のデータを署名付きでやりとりできるトークンです。
認証関連で使われることも多いですが、JWT自体は単なるトークンの形式であり、直接は認証に関係ないです。
JWT (JSON Web Token) とは、任意のJSONデータを格納できるURLセーフな文字列です。
構成としては以下のような3つの情報を .
(ピリオド) でつなげた文字列になっています。
(ヘッダー).(クレーム).(署名)
トークンの形式と署名のバージョンを、URLセーフなBase64でエンコードされたJSON文字列です。
Base64でエンコードされた、任意のデータを含むJSON文字列です。
(※クレーム(claim)には、日本で一般的に使われる「不満を述べる」という意味は含まれないのでご注意ください)
RFCに登録済みのクレーム名(下記)もありますが、使用は必須ではありません。
また任意のフィールドを追加することも可能です。
※登録されているというだけであって、必ずしもこれらを使用する必要はありません。
ヘッダーとペイロードに対しての署名の文字列です。
これによって正しい発行者が発行したIDトークンであることを確認できます。
※リスクもあるので「署名なしのJWTも生成できる」の章も参照してください
JSON Web Tokens - jwt.io に分かりやすい視覚的に分かりやすいサンプルがあったので紹介だけさせていただきます。
調べているうちにいくつかリスクがあることがわかったので、紹介させていただきます。
有効期限などクレームに含めるなどの対策はできますが、一度発行したトークンは取り消すことができません。
発行したトークンをDBなどに保存するなどで対応することは可能ですが、単なるトークンと同等になってしまいます。
むしろDBに問い合わせる必要があるなら、DBにデータを保存して、ランダムなトークンを返す方がよりベターであるとさえ思います。
このことから、JWTは(例えば数分で有効期限が切れるような)有効期限の短いトークンなどの方が向いていると思います。
永続的なセッション管理などには向いていないと私は思いました。
こういう考え方は良いな、と思ったので紹介させていただきます。
「セッションIDをJWTに内包する」 という考え方です。
- 明らかに無効な文字列 "hogehoge"
- JWTのPayloadにあるセッションIDを改竄したもの
- 有効期限が切れたJWT文字列
などを、データストアを参照する前に弾くことができるので、無駄なリクエストを減らすこともできるでしょう。
https://zenn.dev/ritou/articles/4a5d6597a5f250
JWTは実は署名なしで生成することも可能になっています。
RFC 7519 の 6.1. Example Unsecured JWT が残っているように、仕様としては署名なしで作ることはまだ可能なようです。
個人的には署名なしであれば、単にJSON文字列をURLセーフなBase64でエンコードすれば良いだけだと思うので、JWTの仕様に "alg": "None"
があること自体がイマイチである気がします。
セキュアな用途で使うのであれば "alg": "None"
を禁止するべきだと思いました。
私が使っているライブラリだと許可するアルゴリズムを指定できました。
また、単なるURLセーフなBase64でエンコードされたJSONなので、自前でパースしてチェックすることも比較的容易にできます。