0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

本番のJWTを怪しいサイトに貼らない:ブラウザ内で完結するデコードと署名検証

0
Posted at

APIが401を返したとき、Authorization: Bearer eyJ... をコピーして、検索上位のJWTデコーダに貼り付けて exp を見る。よくある流れですが、そのトークンは有効な認証情報そのものです。相手のサーバーでログに残れば、期限が切れるまで誰でも使えてしまいます。

JWTは暗号化されていない

JWTは header.payload.signature の3つをドットでつないだものです。headerとpayloadはbase64urlエンコードされたJSONで、暗号化はされていません。つまりデコードにサーバーは不要です。

ブラウザのコンソールならこれだけです。

const [h, p] = token.split('.');
const dec = s => JSON.parse(atob(s.replace(/-/g, '+').replace(/_/g, '/')));
console.log(dec(h), dec(p));

ブラウザ内で完結するツール

タイムスタンプを読みやすく表示したり、署名検証まで行いたいときは、NibboのJWTデコードを使っています。デコードはページ内のJavaScriptで、署名検証はブラウザ標準のWebCrypto APIで行われます。HS256/384/512は共有シークレット、RS・PS・ES系はPEMまたはJWK形式の公開鍵に対応しています。DevToolsのNetworkタブを開いておけば、トークンが外部に送信されていないことを自分で確認できます。

401の原因になりやすいポイント

  1. exp が過去:exp・iat・nbf はUTCのUnix秒です。JSTの感覚で見ると9時間ずれて混乱しがちです。
  2. nbf が未来:発行側とAPI側のサーバー時刻のずれ。ライブラリのleeway設定で30〜60秒の余裕を持たせます。
  3. aud の不一致:ステージング用に発行したトークンで本番APIを叩いている。
  4. iss の不一致:IdPのテナントURLが末尾のスラッシュやリージョンで違う。
  5. alg の不一致:サーバー側はトークンが名乗る alg を信用せず、固定すること。
  6. 鍵ローテーション:headerの kid に対応する鍵を、APIがまだJWKSから取得していない。

周辺の便利ツール

Basic認証ヘッダやWebhookの本文など、JWT以外にもbase64はよく出てきます。Base64エンコード/デコードやJSON整形も、同じくブラウザ内で処理されるので、社外秘のデータでも安心して使えます。

payloadに入れてはいけないもの

誰でも読めるので、パスワード、APIキー、必要以上の個人情報は入れないこと。トークンの有効期限は短くし、長期のセッションはリフレッシュトークンで扱いましょう。

まとめ

JWTのデコードはただのbase64です。ローカルでデコードし、署名はWebCryptoで検証し、exp/nbf/aud/iss/alg/kid を順に確認すれば、ほとんどの401は解決します。

Nibbo作者 Vitalii

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?