1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

JWTの正しい理解とセキュアな実装ガイド

Last updated at Posted at 2025-06-18

1. 前提知識:暗号化と署名の違い

暗号化(Encryption)の目的と仕組み

暗号化の特徴:

  • データを第三者に読まれないよう秘匿することが目的
  • 適切な復号化キーを持たない者はデータの内容を読めない
  • データの機密性を保護

デジタル署名(Digital Signature)の目的と仕組み

デジタル署名の特徴:

  • データの完全性(改ざんされていないこと)を保証
  • 認証(誰が作成したかの証明)を提供
  • データ自体は暗号化されず、誰でも読める

2. JWTの構造と動作原理

JWTの構造

JWTの実際の形式

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

各部分の説明:

  • Header(赤色部分): Base64エンコードされたヘッダー情報
  • Payload(青色部分): Base64エンコードされたペイロード(暗号化されていない
  • Signature(緑色部分): Header + Payloadの署名

重要なポイント:ペイロードは暗号化されていない

3. 現在の実装における問題点

間違った使用例:機密データをJWTに含める

問題点:

  • 機密情報がBase64エンコードされただけでクライアントに送信
  • 悪意のある第三者が容易に内容を読み取り可能
  • JWTの設計思想と異なる用途での使用

セキュリティリスクの可視化

4. 正しいJWTの使用方法

認証トークンとしての適切な使用

JWTに含めるべき情報 vs 含めるべきでない情報

5. 機密データの適切な取り扱い方法

アーキテクチャパターンの比較

現在の問題のあるパターン

推奨パターン1:サーバーサイド管理

推奨パターン2:適切な暗号化

Ruby on Railsでの実装例

現在の問題のあるコード例

# ❌ 問題のある実装
class AuthenticationController < ApplicationController
  def login
    user = User.find_by(email: params[:email])
    if user&.authenticate(params[:password])
      # 機密情報もJWTに含めている
      payload = {
        user_id: user.id,
        email: user.email,
        credit_card_number: user.credit_card_number, # ❌ 機密情報
        api_key: user.api_key,                       # ❌ 機密情報
        internal_notes: user.internal_notes          # ❌ 機密情報
      }
      
      token = JWT.encode(payload, Rails.application.secret_key_base)
      render json: { token: token }
    end
  end
end

推奨される実装

# ✅ 推奨される実装
class AuthenticationController < ApplicationController
  def login
    user = User.find_by(email: params[:email])
    if user&.authenticate(params[:password])
      # 公開しても問題ない情報のみJWTに含める
      payload = {
        user_id: user.id,
        role: user.role,
        exp: 24.hours.from_now.to_i,
        iat: Time.now.to_i
      }
      
      token = JWT.encode(payload, Rails.application.secret_key_base)
      
      # 機密情報はサーバーサイドで管理
      user.update(last_login_at: Time.current)
      
      render json: { 
        token: token,
        user: {
          id: user.id,
          name: user.name,
          role: user.role
        }
      }
    end
  end
end

# 機密データが必要な場合は別途APIで取得
class UserDataController < ApplicationController
  before_action :authenticate_user!
  
  def show
    # JWTから取得したuser_idを使用して機密データを取得
    user_data = current_user.secure_data
    
    # 必要に応じて暗号化して送信
    encrypted_data = encrypt_sensitive_data(user_data)
    
    render json: { data: encrypted_data }
  end
  
  private
  
  def encrypt_sensitive_data(data)
    # AESなどの適切な暗号化ライブラリを使用
    cipher = OpenSSL::Cipher.new('AES-256-CBC')
    cipher.encrypt
    cipher.key = Rails.application.credentials.encryption_key
    cipher.iv = iv = cipher.random_iv
    
    encrypted = cipher.update(data.to_json) + cipher.final
    Base64.encode64(encrypted)
  end
end

7. まとめ

重要なポイント

結論: JWTは認証のためのツールであり、暗号化のためのツールではありません。機密データの保護には適切な暗号化ライブラリと設計パターンを使用し、JWTは本来の目的である認証と完全性保証に使用することが重要です。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?