JSON Web Token + DataStore で期限付き、無効化可能なトークンを実装する方法
JSON Web Token + DataStore で期限付き、無効化可能なトークンを実装する方法
ritou です。
結構前に JSON Web Signature の署名生成/検証あたりの考え方をまとめた投稿をしました。
JSON Web Signature導入における鍵周りの基本的な考え方
これはいろんなところで JWT(JWS) を使ってる中で署名の鍵をちゃんと整理しないといかんというところから出てきたお話でした。
今回はその "いろんな用途" の中の一つで、"有効期限付き" で "無効化可能" なトークンの実装例を文章化しておきます。
用途
- 何かの処理を始めるときに作成
- 処理をしている中でデータを積んだりする
- 処理が終わったら無効化
みたいな処理を "できるだけ DataStore の利用容量を抑えつつ" 実装するイメージです。
この "処理" の部分が1つであれば "ワンタイム" と言えますが、複数の処理を連動させたりも考慮して "無効化可能" として紹介します。
一般的なWebアプリケーションであればセッション機構を用いて値を積んだり消したりすれば済む程度のことを API ベースでやろうと思った時などに使えると思います。
DataStore
RDB とか NoSQL 、あとはキャッシュのみの利用などの細かいことを意識しないで済むように、ここでは一連の処理の識別子について
- get
- put
- delete
ぐらいしか使わないような実装を意識しています。
関連する仕様
なるべく RFC7519 JSON Web Token (JWT) 日本語訳 で定義されている標準的な Header
/ Payload
を使おうぐらいです。
実装例 : CSRF Tokenみたいなやつ
特別なコンテンツを含まず、自分で生成、検証、無効化する例です。
1. JWT生成
下記のようなHeader / Payloadを作成して JWS を作成します。
鍵周りは上述の記事を参考にしてもらえばと思います。
- Header
-
typ
: (必須)このJWTの種別 -
alg
: (任意) -
kid
: (任意)
-
- Payload
-
usage
: (任意)JWTの用途を入れたりする。Header のtyp
を使っても良さそう。 -
jti
: (必須)識別子。UUID だったり bigint とか。 -
exp
: (必須)有効期限を設定することで、以前発行したトークンの検証をスキップできる。 -
iss
: (任意)発行元 -
aud
: (任意)発行先
-
似たような処理でJWTを使いまくりたくなると思うので(任意)とある部分もなるべく利用するのが良さそうです。
ここで DataStore をどう使うかというあたりで、2種類ぐらいの使い方があるかなと思います。
- 有効な識別子を保存している場合 :
jti
の値を put - 無効化された識別子を保存している場合 : 何もしない
識別子に bigint 的なのを使って生成時に衝突の可能性もある場合、前者のように jti
の値を保存しておきます。
UUID やちょっと前に話題になってた ULID みたいな、識別子がぶつからない仕組みになっている場合は、後者でやると DataStore の容量を節約できそうです。
最後に書いてある "DataStore に残るゴミデータ" についても見ておいてください。
2. JWT検証
- JWTの種別、署名の検証 : 用途の異なる JWT や不正な JWT を除外できる
-
iss
,aud
,exp
の検証 : 古い JWT などを除外できる -
jti
の検証 : 無効化された JWT を除外できる
3 の検証時は、DataStore で以下の処理が行われます。
- 有効な識別子を保存している場合 :
jti
の値で get して値があることを確認 - 無効化された識別子を保存している場合 :
jti
の値で get して値がないことを確認
3. JWT無効化
処理が終わったらこの JWT を無効化する必要があります。
- 有効な識別子を保存している場合 :
jti
の値のデータを delete する - 無効化された識別子を保存している場合 :
jti
の値を put する
これで再度 "2. JWT検証" で jti
の検証が走っても除外することができます。
ちょっと複雑な処理への応用
このやり方は、例えばアカウント新規登録時のようにいくつかのデータを1つずつ受け取って検証、最後にガーッと登録処理を行うような場合にも DataStore 側を拡張せずに利用できます。
センシティブなデータを扱うだったら JWE 使ってもいいと思いますが、お金とかになったらそもそもこんなやり方できないと思うのでその辺はよしなに判断してください。
例えば
- SMS送信による電話番号確認
- ニックネーム設定
- パスワード設定
といった処理を複数のAPIリクエストを用いて行う場合、
- 確認対象(完了前後の)電話番号
- ニックネーム
- パスワード
あたりを JWT の Payload に含んで署名を再生成して引回すことで、最後の本登録の処理の部分までデータを引回すことができます。
ちょっと JWT 関連の処理は増えるものの、DataStoreの方に仮登録状態のようなデータを持たずに識別子の管理だけで実装可能なため、登録処理に必要な情報が増えても割と簡単に対応可能です。たぶん。
DataStore に残るゴミデータ
このような実装は、当然 DataStore にゴミデータみたいなのが残ります。
- 有効な識別子を保存している場合 : JWTの有効期限が切れても無効化されなかった
jti
の値 - 無効化された識別子を保存している場合 : 無効化された
jti
の値
put
する際に JWT の exp
に指定した値をうまく使って定期的に削除を試みるなど、ゴミデータが残りにくい仕組みにしておく必要があるでしょう。
まとめ
- JWTを使った有効期限つき、無効化可能なトークンの作り方を紹介した
- DataStoreの種類にもあんまり影響しない書き方したつもりだけど実際はよしなにやってくれ
- CSRFトークンみたいな使い方や、登録処理のような複数のデータを持ちたい場合にも使えそう
以上です。
ではまた。
Author And Source
この問題について(JSON Web Token + DataStore で期限付き、無効化可能なトークンを実装する方法), 我々は、より多くの情報をここで見つけました https://qiita.com/ritou/items/c9f64b0a45d5ad311e2f著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .