Toolypet
ブログに戻る
Dev

JWT完全ガイド2026 - 構造、セキュリティ、ベストプラクティス総まとめ

JSON Web Tokenの構造と仕組みからセキュリティの脆弱性とベストプラクティスまで。実践的なコード例でJWT認証をマスターします。

Toolypet Team

Toolypet Team

Development Team

6 分で読めます

JWT完全ガイド2026

「JWT?ただのトークンでしょ?」

その通りです。しかし、その「ただのトークン」が正しく実装されていないと、深刻なセキュリティ問題になります。2026年時点で、AI生成の認証コードの48%にセキュリティの脆弱性が存在するという研究結果もあります。

このガイドでは、JWTの構造から実践的なセキュリティのベストプラクティスまで完全に解説します。


JWTとは?

JWT(JSON Web Token)は、二者間で安全に情報を伝達するためのコンパクトで自己完結型の方式です。

主な特徴

特徴説明
Statelessサーバーにセッション保存不要
Self-contained必要な情報がトークン内に含まれる
CompactURL、HTTPヘッダーで使用可能
Signed改ざん検知可能

使用例

  • API認証: Bearerトークンを使用したAPIリクエスト
  • SSO(シングルサインオン): 複数のサービス間での認証共有
  • 情報交換: 署名されたデータの伝達
  • Authorization: 権限/ロール情報の包含

JWT構造

JWTは.(ドット)で区切られた3つのBase64URLエンコードされた部分で構成されます。

xxxxx.yyyyy.zzzzz
  |      |      |
Header  Payload  Signature

1. Header

{
  "alg": "HS256",
  "typ": "JWT"
}
フィールド説明
alg署名アルゴリズム(HS256、RS256など)
typトークンタイプ(JWT)

2. Payload (Claims)

{
  "sub": "user123",
  "name": "山田太郎",
  "email": "yamada@example.com",
  "role": "admin",
  "iat": 1708502400,
  "exp": 1708588800
}

登録済みクレーム(Registered Claims)

クレーム説明
iss発行者(Issuer)"https://auth.example.com"
sub主体(Subject)"user123"
aud対象者(Audience)"https://api.example.com"
exp有効期限(Expiration)1708588800
nbf有効開始時間(Not Before)1708502400
iat発行時間(Issued At)1708502400
jtiJWT固有ID"abc123"

パブリック/プライベートクレーム

{
  "role": "admin",           // プライベートクレーム
  "email": "user@example.com",
  "permissions": ["read", "write"]
}

3. Signature

HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret
)

署名アルゴリズム

対称鍵(Symmetric)

アルゴリズム説明使用例
HS256HMAC + SHA-256単一サーバー、シンプルな実装
HS384HMAC + SHA-384より強力なセキュリティ
HS512HMAC + SHA-512最高レベルのセキュリティ
// Node.js - HS256
const jwt = require('jsonwebtoken');

const token = jwt.sign(
  { userId: 123, role: 'admin' },
  'your-256-bit-secret',  // 同じシークレットで検証
  { algorithm: 'HS256', expiresIn: '1h' }
);

非対称鍵(Asymmetric)

アルゴリズム説明使用例
RS256RSA + SHA-256マイクロサービス、公開検証
RS384RSA + SHA-384高いセキュリティ要件
RS512RSA + SHA-512最高レベルのセキュリティ
ES256ECDSA + P-256短い鍵、モバイル
// RS256 - 非対称
const privateKey = fs.readFileSync('private.pem');
const publicKey = fs.readFileSync('public.pem');

// 発行(Private Key)
const token = jwt.sign(payload, privateKey, { algorithm: 'RS256' });

// 検証(Public Key)
const decoded = jwt.verify(token, publicKey, { algorithms: ['RS256'] });

アルゴリズム選択基準

シナリオ推奨アルゴリズム
単一サーバーHS256
マイクロサービスRS256
公開検証が必要RS256 / ES256
モバイル/IoTES256(短い鍵)

実践的な実装

Node.js (Express)

const express = require('express');
const jwt = require('jsonwebtoken');

const app = express();
const SECRET = process.env.JWT_SECRET; // 環境変数から読み込み

// トークン発行
app.post('/login', async (req, res) => {
  const { email, password } = req.body;

  // ユーザー検証(例)
  const user = await verifyCredentials(email, password);
  if (!user) {
    return res.status(401).json({ error: 'Invalid credentials' });
  }

  const token = jwt.sign(
    {
      sub: user.id,
      email: user.email,
      role: user.role,
    },
    SECRET,
    {
      expiresIn: '1h',
      issuer: 'your-app-name',
    }
  );

  res.json({ token });
});

// ミドルウェアで検証
const authMiddleware = (req, res, next) => {
  const authHeader = req.headers.authorization;

  if (!authHeader?.startsWith('Bearer ')) {
    return res.status(401).json({ error: 'Missing token' });
  }

  const token = authHeader.split(' ')[1];

  try {
    const decoded = jwt.verify(token, SECRET, {
      issuer: 'your-app-name',
      algorithms: ['HS256'],
    });
    req.user = decoded;
    next();
  } catch (err) {
    return res.status(401).json({ error: 'Invalid token' });
  }
};

// 保護されたルート
app.get('/protected', authMiddleware, (req, res) => {
  res.json({ message: `Hello, ${req.user.email}` });
});

Python (FastAPI)

from fastapi import FastAPI, Depends, HTTPException
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
import jwt
from datetime import datetime, timedelta
import os

app = FastAPI()
security = HTTPBearer()
SECRET = os.environ.get("JWT_SECRET")

# トークン発行
def create_token(user_id: str, role: str) -> str:
    payload = {
        "sub": user_id,
        "role": role,
        "iat": datetime.utcnow(),
        "exp": datetime.utcnow() + timedelta(hours=1),
    }
    return jwt.encode(payload, SECRET, algorithm="HS256")

# トークン検証
def verify_token(credentials: HTTPAuthorizationCredentials = Depends(security)):
    token = credentials.credentials
    try:
        payload = jwt.decode(token, SECRET, algorithms=["HS256"])
        return payload
    except jwt.ExpiredSignatureError:
        raise HTTPException(status_code=401, detail="Token expired")
    except jwt.InvalidTokenError:
        raise HTTPException(status_code=401, detail="Invalid token")

# 保護されたエンドポイント
@app.get("/protected")
def protected_route(user: dict = Depends(verify_token)):
    return {"message": f"Hello, {user['sub']}"}

セキュリティの脆弱性と対策

1. Algorithm None攻撃

// 悪意のあるヘッダー
{
  "alg": "none",
  "typ": "JWT"
}

対策:

// 許可するアルゴリズムを明示
jwt.verify(token, secret, { algorithms: ['HS256'] }); // OK
jwt.verify(token, secret); // 危険

2. シークレットキーの脆弱性

// 危険
const SECRET = 'secret123';

// 安全(最低256ビット)
const SECRET = crypto.randomBytes(32).toString('hex');

3. 機密情報の漏洩

// 危険: PayloadはBase64デコード可能
{
  "password": "user_password",  // 絶対禁止!
  "creditCard": "1234-5678-9012-3456"
}

// 安全
{
  "sub": "user123",
  "role": "admin"
}

4. トークン盗難

対策戦略:

  • 短い有効期限(15分〜1時間)
  • Refresh Tokenの使用
  • HTTPS必須
  • HttpOnly Cookie(XSS防止)

5. JWTの再利用(Replay Attack)

// jti(JWT ID)を使用
const token = jwt.sign({
  sub: user.id,
  jti: crypto.randomUUID(), // 一意のID
}, SECRET);

// サーバーでjtiブラックリストを管理

Access Token + Refresh Token

なぜ必要か?

トークン有効期間用途
Access Token15分〜1時間API認証
Refresh Token7日〜30日Access Tokenの更新

実装例

// ログイン時に両方のトークンを発行
app.post('/login', async (req, res) => {
  const user = await verifyCredentials(req.body);

  const accessToken = jwt.sign(
    { sub: user.id, type: 'access' },
    ACCESS_SECRET,
    { expiresIn: '15m' }
  );

  const refreshToken = jwt.sign(
    { sub: user.id, type: 'refresh' },
    REFRESH_SECRET,
    { expiresIn: '7d' }
  );

  // Refresh TokenはHttpOnly Cookieで
  res.cookie('refreshToken', refreshToken, {
    httpOnly: true,
    secure: true,
    sameSite: 'strict',
    maxAge: 7 * 24 * 60 * 60 * 1000,
  });

  res.json({ accessToken });
});

// トークン更新
app.post('/refresh', (req, res) => {
  const refreshToken = req.cookies.refreshToken;

  try {
    const decoded = jwt.verify(refreshToken, REFRESH_SECRET);

    const newAccessToken = jwt.sign(
      { sub: decoded.sub, type: 'access' },
      ACCESS_SECRET,
      { expiresIn: '15m' }
    );

    res.json({ accessToken: newAccessToken });
  } catch (err) {
    res.status(401).json({ error: 'Invalid refresh token' });
  }
});

JWTデバッグ

トークンのデコード

JWT Decoderにトークンを貼り付けると:

  • Headerの確認
  • Payloadの確認
  • 有効期限の確認
  • 署名の検証(シークレット入力時)

CLIでデコード

# Headerデコード
echo "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9" | base64 -d

# Payloadデコード
echo "eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4ifQ" | base64 -d

ベストプラクティスチェックリスト

発行

  • 強力なシークレットキー(256ビット以上)
  • アルゴリズムを明示(HS256、RS256)
  • 短い有効期限(15分〜1時間)
  • 必須クレームを含める(sub、iat、exp、iss)
  • 機密情報を含めない

検証

  • アルゴリズムホワイトリスト(algorithms: ['HS256']
  • 有効期限の検証
  • 発行者(iss)の検証
  • 対象者(aud)の検証

保存と送信

  • HTTPS必須
  • HttpOnly Cookie(XSS防止)
  • SameSite属性(CSRF防止)
  • localStorageを避ける(XSS脆弱)

FAQ

Q1: JWT vs セッション、いつどちらを使う?

A:

  • JWT: ステートレスAPI、マイクロサービス、モバイルアプリ
  • セッション: 従来のWebアプリ、サーバーサイドレンダリング、即時ログアウトが必要な場合

Q2: JWTが盗まれたら?

A: Access Tokenは有効期限まで有効です。したがって:

  • 短い有効期限を設定(15分)
  • Refresh Token Rotation
  • 疑わしい場合は全トークンを無効化

Q3: なぜlocalStorageに保存してはいけないのですか?

A: XSS攻撃に脆弱です。JavaScriptでアクセス可能なため、悪意のあるスクリプトがトークンを盗む可能性があります。HttpOnly Cookieの方が安全です。

Q4: RS256はHS256より安全ですか?

A: 「より安全」というより「用途が異なる」です。

  • HS256: 同じシークレットを共有、単一サーバー
  • RS256: 公開鍵で検証、複数サービス

Q5: トークンブラックリストは必要ですか?

A: 即時ログアウトが必要な場合は必要です。ただし、ステートレスの利点が減ります。短い有効期限 + Refresh Tokenが代替案です。


まとめ

JWTセキュリティの要点:

  1. 強力なシークレット: 256ビット以上のランダム
  2. アルゴリズム検証: ホワイトリスト方式
  3. 短い有効期間: Access 15分、Refresh 7日
  4. 安全な保存: HttpOnly + Secure Cookie
  5. 機密情報を除外: Payloadは誰でもデコード可能

関連ツール

ツール用途
JWT DecoderJWTデコードと検証
Base64 EncoderBase64エンコード/デコード
Hash Generatorハッシュ生成
JWT認証セキュリティAPIWeb開発トークン

著者について

Toolypet Team

Toolypet Team

Development Team

The Toolypet Team creates free, privacy-focused web tools for developers and designers. All tools run entirely in your browser with no data sent to servers.

Web DevelopmentCSS ToolsDeveloper ToolsSEOSecurity