JWT(JSON Web Token)は、ログイン後の認証情報をやり取りする方法として、Web APIやシングルページアプリケーションで広く使われています。
便利な一方で、仕組みを正しく理解せずに使うと、セキュリティ上の問題を招きます。
この記事では、JWTの構造と、実装前に押さえておきたい注意点を整理します。
JWTの3つの構造
JWTは、ピリオド(.)で区切られた3つの部分からなる文字列です。
ヘッダー.ペイロード.署名
- ヘッダー:署名のアルゴリズム(例:HS256、RS256)やトークンの種類を示すJSON。
- ペイロード:ユーザーIDや有効期限などの情報(クレーム)を含むJSON。
- 署名:ヘッダーとペイロードが改ざんされていないことを検証するための値。
ヘッダーとペイロードは、JSONをBase64URL形式でエンコードしたものです。
これは暗号化ではなく、誰でも元のJSONに戻せます。
よく使われるクレーム
| クレーム | 意味 |
|---|---|
| iss | 発行者(issuer) |
| sub | 対象者(subject)。 多くの場合ユーザーID |
| aud | 想定している受け手(audience) |
| exp | 有効期限(UNIXタイム) |
| nbf | この時刻より前は無効(not before) |
| iat | 発行時刻(issued at) |
exp などの時刻はUNIXタイム(秒)で表されます。
人間が読める日時に変換して確認したいときは、UNIXタイム変換ツールが便利です。
署名の方式:HS256とRS256
- HS256(共通鍵):発行と検証に同じ秘密鍵を使う。
構成はシンプルだが、検証する側も秘密鍵を持つ必要があるため、複数のサービスで共有する場合は漏えいに注意が必要だ。 - RS256(公開鍵):秘密鍵で署名し、公開鍵で検証する。
検証側に秘密鍵を渡さずに済むため、複数サービス間でトークンを検証する構成に向いている。
実装時の注意点
1. ペイロードは暗号化されていない
署名はあくまで「改ざん検知」であり、内容の秘匿ではありません。
パスワードや個人情報、機密性の高い情報をペイロードに入れてはいけません。
2. 署名と有効期限を必ず検証する
デコードして中身を読めることと、トークンが正当であることは別です。
サーバー側では、署名、exp、aud、iss を必ず検証します。
3. アルゴリズムを固定する
ヘッダーのalgに「none」(署名なし)を指定した偽造トークンを受け入れてしまう実装上の脆弱性が、過去に知られています。
検証時は、サーバー側で許可するアルゴリズムを明示的に指定し、ヘッダーの値を鵜呑みにしないでください。
4. 有効期限は短めに設定する
JWTは発行後に取り消しにくいという性質があります。
アクセストークンの有効期限は短く(数分〜1時間程度)し、必要に応じてリフレッシュトークンで更新する設計が一般的です。
5. 保存場所に気を付ける
ブラウザのlocalStorageに保存すると、XSS(クロスサイトスクリプティング)でトークンを盗まれるおそれがあります。
HttpOnly属性・Secure属性付きのCookieに保存する方法もありますが、その場合はCSRF対策が必要です。
どちらにも一長一短があるため、アプリケーションの特性に合わせて選びます。
JWTを使うべきか
JWTは、サーバー側でセッション状態を持たずに認証したい場合や、複数のサービス間で認証情報を受け渡す場合に有効です。
一方、単一のWebアプリケーションで、ログアウトや強制失効を確実に行いたい場合は、従来のサーバーセッションのほうがシンプルで安全なこともあります。
「流行っているから」ではなく、要件に合わせて選択しましょう。
まとめ
JWTは「署名された、読めるデータ」です。
暗号化されていないこと、検証を省略してはいけないこと、有効期限を短くすることの3点を押さえておけば、多くの典型的なミスを避けられます。
開発中にトークンの中身を確認したいときは、デコードツールを活用してください。
ただし、本番環境の有効なトークンを第三者のサービスに入力することは避けましょう。