JWT認証、便利だしDBに状態持たないのでRESTfulだしめちゃ便利です。
今回はトークン生成、検証と脆弱性についてまとめました。
ざっくりまとめてるので網羅してないし説明不足な部分もあります。
目次
JWTトークン生成の仕組み
まずはトークン生成から。
- フロントエンド側はユーザー・パスワードを送信
- バックエンド側はユーザー・パスワードが正しいかを検証しユーザー情報取得
- DBにユーザー情報が保存されてる前提で進めます
- パスワードはハッシュ化などしてください
- ユーザー情報からpayloadを作成
- ユーザーIDなどが一般的
- payloadはデコードが容易なのでパスワードなどの機密情報は入れない
- ハッシュ化するアルゴリズムなどの設定値を指定したヘッダーを作成
- ヘッダー・payloadをBase64エンコードする
- デコード可能
- 5の値をバックエンド側が保持している秘密鍵でハッシュ化・署名
- 5の値(ヘッダー、payload)と6の署名を「.」でつなげたものがJWTトークンとなる

JWTトークン検証の仕組み
次に検証ですが、基本的におなじ流れです。
- フロントエンド側は生成されたJWTトークンをバックエンド側に送信
- Authorizationヘッダーなどに入れるのが一般的
- バックエンド側はヘッダー・payloadをデコードして、ユーザー情報・アルゴリズムなどの設定値を取得
- 指定されたアルゴリズムを使って、ヘッダー・payloadからバックエンド側が保持している秘密鍵を使って署名を算出
- 送信されてきたトークンの署名と一致していれば認証成功、デコードしたpayloadのユーザー情報が示すユーザーからのログインと判定

安全性根拠など
非常にシンプルなのでこれで大丈夫?と思う人いるかもしれませんが、以下のような理由が安全性の根拠です。
- バックエンド側のみが保持する秘密鍵でハッシュ化するので改ざんを検知できる
- ヘッダーやpayloadが改ざんされていたら署名が一致しない
- 秘密鍵が十分に長ければ別の値(別のpayloadなど)から同じ署名を作れない
- brute forceで突破されない
脆弱性
基本的にライブラリの使い方や秘密鍵の長さに気を付けていれば問題ないですが、以下のような脆弱性があります。
- アルゴリズムでnoneを許容すると署名作成の際にハッシュ化されないため、改ざんができてしまう = none attack
- ライブラリの設定で防げるし、秘密鍵を指定したらデフォルトで受け付けない場合がほとんど
- 秘密鍵が短いとbrute forceで突破できてしまう
- 256bitなどの長さならほぼ問題ない
- 256bit以上が推奨されている