JWT の基本とトークン構造
JWT(JSON Web Token)は、ユーザー認証や情報の保持 に使われるトークン方式であり、以下の 3 つの要素で構成されます。
- ヘッダ(Header)
- 暗号化アルゴリズム(例: HS256)
- トークンのタイプ(通常は "JWT")
- ペイロード(Payload)
- ユーザー情報(個人情報は含めない)
- 発行時間(iat)、有効期限(exp)などのメタ情報
- 署名(Signature)
ヘッダとペイロードを 秘密鍵 で署名する
JWT は改ざん防止されるが、暗号化されていないため、ペイロードの情報は見られるところにおくと誰でもデコードして内容を見ることができる。
そのため、パスワードや個人情報を含めるのはNG!
推奨される JWT 生成方法
// jwtsecret は base64エンコードされた秘密鍵情報
// JWT_SECRET を Base64 デコードして Key オブジェクトを作成
byte[] keyBytes = Decoders.BASE64.decode(jwtSecret);
Key key = Keys.hmacShaKeyFor(keyBytes);
String token = Jwts.builder()
.subject(oauth2User.getName()) // ユーザー識別子
.issuedAt(new Date()) // 発行時間
.expiration(new Date(System.currentTimeMillis() + 86400000)) // 有効期限 1日
.signWith(key) // 署名の適用(生の文字列を禁止)
.compact();
新しい Jwts.builder() の改善点
✅ signWith(key) に変更 → Base64 デコードした Key オブジェクトを必須に
✅ 生のパスワード文字列を誤って使うリスクがなくなった
✅ null の場合はプロパティを生成しないため、コンパクトなトークンが作成される
現在は推奨されていない JWT 生成方法
emailをプロパティとしてtoken生成しているので アンチパターンでもあります
String token = Jwts.builder()
.setSubject(oauth2User.getName())
.claim("email", email)
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + 86400000)) // 有効期限を1日に設定
.signWith(SignatureAlgorithm.HS256, JWT_SECRET)
.compact();
JWTのアンチパターン
JWT は 署名による改ざん防止 はできるが、ペイロードの内容は誰でも閲覧可能!
そのため、以下のような個人情報は 絶対に含めてはいけません!
{
"user_id": "12345",
"email": "user@example.com",
"password": "secret123"
}
JWT に個人情報を入れてはいけない理由
❌ JWT の内容は Base64 デコードすれば誰でも見られる
❌ 攻撃者が取得した場合、情報漏洩のリスク
❌ ログやデバッグ時にトークンの内容が記録される可能性あり
対策
✅ 個人情報は JWT に含めず、暗号化されたセッションストレージに保存する
✅ 短い有効期限 (exp) を設定し、長期トークンはリフレッシュトークンを使用する
まとめ
JWT の実装ポイント
✅ 推奨: signWith(key) に変更し、秘密鍵は Base64 デコードして Key オブジェクト化する
✅ JWT にパスワードや個人情報を含めない!
JWT を正しく使えば、セキュアで拡張性のある認証システムを構築できる!
間違った実装を防ぎ、安全に運用しよう!🔥