jwt フックは、アルゴリズムを固定していない JWT 検証と、検証そのものを無効にしている箇所を指摘します。前者は、検証側がトークン自身の alg ヘッダーを信頼してしまうアルゴリズム混同の穴です。言語を識別して動作し、各ファイルをそのファイルが使う JWT ライブラリに合わせて読み取ります。また、federation 専門知識 を支える決定論的なエンジンでもあり、scan モードまたは check モードで自分で実行することもできます。
実行方法
- コードベースをスキャン
- 呼び出しをチェック
npx lagune read jwt # scans the whole project
npx lagune read jwt --dir src # scans a directory
npx lagune read jwt --file auth.ts # scans a single file
npx lagune read jwt --lang javascript --pattern 'jwt.verify(token, secret)' # => unpinned
npx lagune read jwt --lang python --pattern 'jwt.decode(t, k, options={"verify_signature": False})' # => unpinned
npx lagune read jwt --lang python --pattern 'jwt.decode(t, k, algorithms=["HS256"])' # => safe
Unpinned JWT verification found の下に並ぶ各行は、algorithms の許可リストを設定していない(ライブラリが必要とする場合)、安全でない許可リストを受け入れている(none、または非対称アルゴリズムと HMAC の混在)、あるいは署名の検証を完全に無効にしているために、トークン自身の alg を信頼してしまう検証呼び出しです。これは確定したリスクの露出なので、フックは 0 以外の終了コードで終了します。何も見つからなければ no unpinned JWT verification found と出力します。
判定の読み方
| 判定 | 意味 |
|---|---|
unpinned | アルゴリズムの許可リストがない(必要な場合)、許可リストが安全でない、または検証が無効になっている検証呼び出し。 |
safe | 適切なアルゴリズムの許可リストで固定している、またはライブラリが暗黙的に固定している検証呼び出し。 |
invalid | 判定できる検証呼び出しがコードスニペットに見当たらない。 |
CLI オプション
| オプション | 値 | 説明 |
|---|---|---|
--pattern | コードスニペット | 1 つの呼び出しをチェックする。繰り返し指定すると複数をチェックし、1 行に 1 つずつ判定を出力する。 |
--lang | 言語 | --pattern を使うときは必須:javascript、python、go、java、kotlin、php、ruby、rust、csharp のいずれか。 |
--dir | ディレクトリ | スキャン対象をディレクトリに絞る。繰り返し指定でき、--file と併用できる。 |
--file | ファイル | スキャン対象を 1 つのファイルに絞る。繰り返し指定でき、--dir と併用できる。 |
オプションを指定しなければ、プロジェクト全体をスキャンします。--pattern には --lang が必要で、--dir や --file とは併用できません。
対応言語
スキャンはファイル拡張子をもとに、次のライブラリを読み取ります。ライブラリによってはアルゴリズムを暗黙的に固定する(明示的なリストがなくても安全な)ため、"許可リストなし ⇒ unpinned" というルールは、明示的なリストを前提とするライブラリにだけ適用されます。そのため、正しく設定された呼び出しが指摘されることはありません。
| 言語 | ライブラリ | 許可リストなしを unpinned として指摘するか | 常に指摘するもの |
|---|---|---|---|
| JavaScript / TypeScript | jsonwebtoken、jose | はい | none、非対称アルゴリズムと HMAC の混在 |
| Python | PyJWT、python-jose | はい(PyJWT は指定が必須、python-jose はデフォルトが algorithms=None) | none、verify_signature: False |
| Go | golang-jwt | はい(WithValidMethods がない場合) | none、ParseUnverified |
| Ruby | ruby-jwt | はい | none、verify = false |
| Java / Kotlin | jjwt、nimbus | いいえ(鍵から導出) | none、署名なし/unsecured のパーサー |
| PHP | firebase/php-jwt | いいえ(Key がアルゴリズムを保持) | none |
| Rust | jsonwebtoken | いいえ(Validation が指定を必須とする) | none、insecure_disable_signature_validation |
| C# | Microsoft.IdentityModel | いいえ(パラメーターが複数行にまたがる) | none、RequireSignedTokens = false |
フックが判定するのはアルゴリズムの固定だけで、クレーム、鍵、フローのチェックといった判断は、引き続き federation 専門知識 が担います。
よくある質問
トークンのヘッダーからアルゴリズムを読み取る検証処理では、攻撃者が RS256 を HS256 にすり替え、公開鍵で署名できてしまいます。適切なアルゴリズムの許可リストをコードで固定すれば防げます。jwt フックは、許可リストを設定していない、または安全でない許可リストを使っている検証呼び出しを指摘します。
