JWT(JSON Web Token)完全理解ガイド
1. JWTの基本構造
JWTは3つの部分から構成される文字列です:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIn0.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
構造: ヘッダー.ペイロード.署名
各部分の役割
部分 | 内容 | エンコード方式 | 可逆性 |
---|---|---|---|
ヘッダー | アルゴリズム情報 | Base64URL | 可逆(デコード可能) |
ペイロード | ユーザー情報、有効期限等 | Base64URL | 可逆(デコード可能) |
署名 | 改ざん検証用のハッシュ値 | 署名アルゴリズム依存 | 不可逆 |
具体例
// ヘッダー(JSON → Base64URL)
const header = {
"alg": "HS256", // アルゴリズム
"typ": "JWT" // トークンタイプ
};
// ペイロード(JSON → Base64URL)
const payload = {
"user_id": 123,
"name": "John Doe",
"exp": 1672531200 // 有効期限
};
// 署名(ハッシュ値)
const signature = HMAC_SHA256(base64Url(header) + "." + base64Url(payload), secretKey);
2. 全体的なフロー
ログイン〜API利用までの流れ
クライアント側の処理
// 1. ログイン
const login = async (credentials) => {
const response = await fetch('/api/login', {
method: 'POST',
body: JSON.stringify(credentials)
});
const { token } = await response.json();
// 2. JWTをそのまま保存(一切変更しない)
localStorage.setItem('jwt', token);
};
// 3. API呼び出し時
const callAPI = async () => {
const token = localStorage.getItem('jwt');
const response = await fetch('/api/protected', {
headers: {
'Authorization': `Bearer ${token}` // そのまま送信
}
});
};
3. デジタル署名の仕組み
3.1 HMAC方式(対称鍵)
JWTで最も一般的な方式です。
特徴
- 軽量: 処理が高速
- シンプル: 鍵管理が簡単
- 制限: 全サービスが同じ秘密鍵を共有する必要
3.2 RSA方式(非対称鍵)
マイクロサービス環境に適した方式です。
マイクロサービス環境での利点
利点:
- 権限分離: 認証サーバーのみがJWT発行可能
- セキュリティ: 公開鍵漏洩でもJWT作成不可
- スケーラビリティ: 新サービス追加時は公開鍵配布のみ
4. 改ざん検出の仕組み
攻撃者が改ざんを試みた場合
ハッシュ関数の雪崩効果
// わずかな変更でも大きくハッシュ値が変化
const original = '{"user_id":123,"role":"user"}';
const modified = '{"user_id":123,"role":"admin"}'; // 1文字違い
const hash1 = SHA256(original); // "a1b2c3d4e5f6..."
const hash2 = SHA256(modified); // "x9y8z7w6v5u4..." (完全に異なる)
5. セキュリティ考慮事項
重要なポイント
- トークンの有効期限: 適切な期限設定でリスク軽減
- リフレッシュトークン: 長期間の認証維持
- XSS対策: CSP設定とhttpOnly Cookieの検討
- 鍵管理: 秘密鍵の厳重な管理
Vue.js + TypeScriptでの実装例
// composables/useAuth.ts
export const useAuth = () => {
const isAuthenticated = ref(false);
const user = ref<User | null>(null);
const login = async (credentials: LoginCredentials) => {
const response = await authAPI.login(credentials);
const token = response.data.token;
// JWTをそのまま保存
localStorage.setItem('jwt-token', token);
isAuthenticated.value = true;
user.value = response.data.user;
};
const checkAuthStatus = () => {
const token = localStorage.getItem('jwt-token');
if (token && !isTokenExpired(token)) {
isAuthenticated.value = true;
}
};
return {
isAuthenticated: readonly(isAuthenticated),
user: readonly(user),
login,
checkAuthStatus
};
};
6. まとめ
JWTの核心メカニズム
- ステートレス認証: サーバー側でセッション保持不要
- 改ざん検出: デジタル署名によるデータ整合性保証
- 権限分離: 認証サーバーと各サービスの責務分離
- スケーラビリティ: マイクロサービス環境に最適
理解のポイント
- クライアント側: JWTを一切変更せず、そのまま保存・送信
- サーバー側: 署名検証により改ざんの有無を確実に検出
- セキュリティ: ハッシュ値の比較により、わずかな改ざんも検出可能
- 実装: フロントエンドでの状態管理と適切なAPI呼び出し
JWTは「データの改ざん = ハッシュ値の変化 = 署名との不一致 = 改ざん検出」という連鎖により、堅牢なセキュリティを実現しています。