JWT をデコードしてそのクレームを安全に検査する方法
簡単な回答
JWT は、header.payload.signature というドットで結合された 3 つの Base64URL 文字列です。 Base64URL デコードを使用してヘッダーとペイロードをデコードしてクレームを検査します。ただし、デコードはデータを読み取るだけであり、信頼性は検証されません。主張を信頼する前に、必ずサーバー上の署名を確認してください。 JWT デコーダを使用して、ブラウザ内のトークンを検査します。
導入
JSON Web トークン (JWT、RFC 7519) は、認証と認可に使用されるコンパクトで URL に安全なトークン形式です。これには、ドットで区切られた 3 つの Base64URL エンコードされた部分 (header.payload.signature) があります。ヘッダーにはアルゴリズムが記述され、ペイロードにはクレーム (ユーザー ID、ロール、有効期限) が含まれ、署名はトークンが信頼できる当事者によって発行されたことを証明します。重要なのは、ヘッダーとペイロードは暗号化されているのではなくエンコードされているため、誰でも読み取ることができます。
ステップバイステップ
-
トークンを 3 つの部分に分割する
JWT は xxxxx.yyyyy.zzzzz のようになります。ドット文字で分割して、ヘッダー (パート 0)、ペイロード (パート 1)、および署名 (パート 2) を取得します。正確に 3 つの部分が存在しない場合、トークンの形式は不正です。
-
Base64URL ヘッダーをデコードする
ヘッダーは、{"alg":"HS256","typ":"JWT"} のような Base64URL エンコードされた JSON オブジェクトです。 Base64URL では、+ と / の代わりに - と _ が使用され、パディングが省略されます。それをデコードして、JSON.parse を実行してアルゴリズムと型を読み取ります。 JWT デコーダーはこれを自動的に行います。
-
ペイロード (クレーム) を Base64URL デコードします。
ペイロードはクレームの JSON オブジェクトです。登録されたクレームには、iss (発行者)、sub (件名)、aud (対象者)、exp (有効期限)、nbf (not-before)、iat (発行時)、および jti (トークン ID) が含まれます。プライベート クレームはアプリケーション固有です (ロール、電子メールなど)。デコードして検査しますが、検証されるまでは信頼しないでください。
-
有効期限と未期限の請求を確認する
exp と nbf は Unix タイムスタンプ (秒) です。現在時刻が exp を超えている場合、トークンの有効期限が切れているため、拒否する必要があります。現在時刻が nbf より前の場合、トークンはまだ有効ではありません。 UX についてはクライアント側でこれらを確認しますが、セキュリティのためにサーバー側で強制します。
-
サーバー上の署名を検証します (決してクライアント側ではありません)
署名は、HS256 の場合は HMAC-SHA256(secret, header.payload)、RS256/ES256 の場合は RSA/ECDSA 署名です。検証には秘密キーまたは公開キーが必要ですが、これらはブラウザーに決して到達してはなりません。 jsonwebtoken (ノード) や jose などのライブラリを使用して検証してください。決して独自の暗号を作成しないでください。
例
典型的な JWT (3 つの部分)
入力: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpmeJf36POk6yJV_adQssw5c
出力: Header: {"alg":"HS256","typ":"JWT"} Payload: {"sub":"1234567890","name":"John Doe","iat":1516239022}
標準クレームを含むデコードされたペイロード
入力: 本物の認証トークンのペイロード
出力: {"sub":"user-42","iss":"freeonlinetoolsgo.com","exp":1767229200,"iat":1767225600,"role":"admin"}
期限切れトークンの検出
入力: exp: 1609459200 (2021-01-01) 2026-08-28 にチェック
出力: Token is expired —current time (1767225600) > exp (1609459200). Reject and prompt re-login.
よくある問題
- デコードを検証として扱う: 誰でも任意のクレームと偽の署名を含む JWT を作成できます。デコードするとペイロードが読み取られますが、何も証明されません。クレームを信頼する前に、必ずサーバー上の秘密/公開キーを使用して署名を検証してください。
- 「none」アルゴリズムの使用: JWT 仕様では、安全でないトークンに対して alg: none が許可されています。検証者が alg: none を受け入れる場合、攻撃者はトークンを偽造できます。何も拒否せず、予想されるアルゴリズムをホワイトリストに登録するようにライブラリを構成します。
- JWT を localStorage に保存する: XSS は localStorage を読み取り、トークンを抽出できます。セッション トークンには、httpOnly、Secure、SameSite=Strict Cookie、またはリフレッシュ トークン Cookie を使用した短期間のメモリ内トークンを優先します。
- exp/aud/iss をチェックしない: 盗まれたトークンは有効期限が切れるまで有効です。サービス間でのトークンの再実行を防ぐために、リクエストごとに exp (有効期限)、aud (対象ユーザー)、および iss (発行者) を常にチェックしてください。
ヒント
- 有効期間の短いアクセス トークン (15 分) と有効期間の長いリフレッシュ トークンを使用します。これにより、アクセス トークンが盗まれた場合のウィンドウが制限されます。
- 複数のサービスがトークンを検証する場合は、HS256 (対称) よりも RS256 (非対称) を優先します。各サービスが公開キーを取得し、発行者のみが秘密キーを持ちます。
- 開発中に JWT デコーダーを使用して、サーバーが発行している内容を検査します。トークンをどこにも送信せずに、デコードされたヘッダー、ペイロード、人間が判読できるクレームの概要を表示します。
- JWT ペイロードには機密データ (パスワード、PII) を決して入れないでください。ペイロードは Base64 でエンコードされており、暗号化されていないため、トークンを傍受した人はすべてのクレームを読み取ることができます。