chakokuのブログ(rev4)

テック・コミック・ごくまれにチャリ

署名付きJWTの検証

前回は手動でJWTを取得するところまではできた。公開鍵による署名の検証ができずにいた。JWTの解説文書*1があり、JSによる検証手順が書かれていたので、まずはこれを動かしてみる*2
4.2.2 RS256: RSASSA + SHA256 より

// You can get this from private_key.pem above.
const privateRsaKey = `<YOUR-PRIVATE-RSA-KEY>`;
const signed = jwt.sign(payload, privateRsaKey, {
algorithm: 'RS256',
expiresIn: '5s'
});
// You can get this from public_key.pem above.
const publicRsaKey = `<YOUR-PUBLIC-RSA-KEY>`;
const decoded = jwt.verify(signed, publicRsaKey, {
// Never forget to make this explicit to prevent
// signature stripping attacks.
algorithms: ['RS256'],
});

verifyに入力しているのは、署名と公開鍵、関数を実行して得られるのは、、payloadのSHA256の値か??

しかし、、
公開鍵署名アルゴリズムの場合:

const encodedHeader = base64(utf8(JSON.stringify(header)));
const encodedPayload = base64(utf8(JSON.stringify(payload)));
const signature = base64(rsassa(`${encodedHeader}.${encodedPayload}`,
privateKey, sha256));

とも書かれているので、header + "." + payloadの文字列を秘密鍵で署名している。

署名は、RSASSAであり、これはまず電文からハッシュを作成して、ハッシュに対して秘密鍵で署名している。
暗号用語の体系的整理 | オブジェクトの広場

JavaScriptではライブラリなので、詳細ちょっと分からない(JSに疎いので)。こうなったら、、前回取得したJWTに対してPythonのJWTライブラリで検証する。結果がTrueになったら、デバッグモードで動かして、Python内でどういう手順で検証しているのかを調べることで検証の仕組みを理解したい。

GitHub - jpadilla/pyjwt: JSON Web Token implementation in Python

#!/usr/bin/python3
# https://pyjwt.readthedocs.io/en/stable/usage.html

import jwt

# pubkey: 0cc175b9c0f1b6a831c399e269772661
PUBLIC_KEY = b"""-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBC
    *略*
ekrRBP+R3xEUeMFf5z1HeQNK8sjZe
RwIDAQAB
-----END PUBLIC KEY-----"""

JWT = "eyJ0eXAiOiJKV1QiLCJhbGciOiJ*略*Y8kw4gg"

encoded = JWT
try:
  jwt.decode(encoded, PUBLIC_KEY, algorithms=["RS256"])
except Exception as e:
  print("JWT Error")
  print(e)

上記プログラムを実行すると、Signature verification failedでエラーになった。だから、、公開鍵を間違っているかなにかで整合性がおかしいようだ。
もう一度認証フローを流してJWTを取り直してみよう。次はGoogleAPIを叩くか・・

*1:Auth0が出している、JWT ハンドブック

*2:以下の例では、いずれも⼀般的に使われている jsonwebtoken JavaScript ライブラリを利⽤しています・・・これではどう動ているのか分からん