JavaにおけるJJWTライブラリを利用したJSON Web Token (JWT) の実装ガイド

JJWT(Java JWT)は、Java環境でJSON Web Token(RFC 7519)を扱うための、直感的で強力なライブラリです。デジタル署名(JWS)や暗号化(JWE)などの仕様をサポートしており、マイクロサービス間の認証やセッション管理に広く利用されています。

Maven依存関係のセットアップ

プロジェクトでJJWTを利用するには、pom.xmlに以下の依存関係を追加します。APIインターフェース、実装、およびJSON処理用のJackson実装を定義します。

<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-api</artifactId>
    <version>0.12.5</version>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-impl</artifactId>
    <version>0.12.5</version>
    <scope>runtime</scope>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-jackson</artifactId>
    <version>0.12.5</version>
    <scope>runtime</scope>
</dependency>

JWTの生成(署名付き)

HMAC-SHAアルゴリズムを使用して、秘密鍵による署名付きトークンを発行する基本的な方法です。

import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys;
import javax.crypto.SecretKey;
import java.util.Date;

// 署名用の秘密鍵を生成
SecretKey signingKey = Jwts.SIG.HS256.key().build();

// トークンの構築
String jwtToken = Jwts.builder()
    .subject("member_456")
    .claim("role", "editor")
    .claim("email", "dev@example.com")
    .issuedAt(new Date())
    .signWith(signingKey)
    .compact();

JWTの検証とパース

受け取ったトークンを検証し、ペイロードから特定のクレーム(情報)を取得する処理です。

try {
    var claims = Jwts.parser()
        .verifyWith(signingKey)
        .build()
        .parseSignedClaims(jwtToken)
        .getPayload();

    String userId = claims.getSubject();
    String userRole = claims.get("role", String.class);
    
    System.out.println("User ID: " + userId);
} catch (io.jsonwebtoken.JwtException e) {
    // 署名不正や改ざん、有効期限切れのハンドリング
    System.err.println("Invalid Token: " + e.getMessage());
}

有効期限の設定

セキュリティを担保するため、トークンには必ず有効期限を設定する必要があります。Java 8のTime APIを利用した設定例です。

import java.time.Instant;
import java.time.temporal.ChronoUnit;

Instant currentTime = Instant.now();
Instant expireTime = currentTime.plus(30, ChronoUnit.MINUTES);

String shortLivedToken = Jwts.builder()
    .issuedAt(Date.from(currentTime))
    .expiration(Date.from(expireTime))
    .subject("auth_user")
    .signWith(signingKey)
    .compact();

RSA非対称鍵による署名

公開鍵と秘密鍵を使用して、署名と検証を行う方法です。認証サーバーが秘密鍵で署名し、リソースサーバーが公開鍵で検証する場合に適しています。

import java.security.KeyPair;

// RSA鍵ペアの生成
KeyPair pair = Jwts.SIG.RS256.keyPair().build();

// 秘密鍵で署名
String rsaSignedJwt = Jwts.builder()
    .subject("secure_api_access")
    .signWith(pair.getPrivate())
    .compact();

// 公開鍵で検証
var parsedData = Jwts.parser()
    .verifyWith(pair.getPublic())
    .build()
    .parseSignedClaims(rsaSignedJwt);

主なクレーム設定メソッド

  • issuer(String): トークンの発行者を識別する文字列。
  • audience(String): トークンの利用対象となる受信者。
  • notBefore(Date): この時刻より前にはトークンを有効とみなさない。
  • id(String): トークンの一意識別子(JTI)。リプレイ攻撃対策に使用。

例外クラスの分類

JJWTでは、検証失敗の原因に応じて特定の例外がスローされます。

  • ExpiredJwtException: 有効期限が切れている場合。
  • MalformedJwtException: JWTの構造(ヘッダー、ペイロード、署名の区切り等)が壊れている場合。
  • SignatureException: 署名の不一致(改ざんの可能性)がある場合。
  • UnsupportedJwtException: ライブラリがサポートしていない形式やアルゴリズムの場合。

運用上の留意点

  1. 機密情報の扱い: ペイロードはBase64Urlでエンコードされているだけであり、誰でもデコード可能です。パスワードなどの機密情報は含めないでください。
  2. 適切なアルゴリズムの選択: 要件に応じてHS256(共通鍵)やRS256(公開鍵)を選択し、鍵の長さも十分な強度を確保してください。
  3. トランスポート層の保護: トークンの盗聴を防ぐため、常にHTTPS経由で転送してください。
  4. 鍵のローテーション: 万が一の漏洩に備え、署名鍵は定期的に更新する仕組みを導入することが推奨されます。

タグ: JWT Java JJWT Security authentication

6月25日 17:14 投稿