0
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?

License System Day 9: 改ざん防止の仕組み

Last updated at Posted at 2025-12-08

🎄 科学と神々株式会社アドベントカレンダー 2025

License System Day 9: 改ざん防止の仕組み


📖 今日のテーマ

セキュリティ基礎編の最終回です。今日は攻撃者の視点から、なぜ署名が改ざんを防げるのかを学びます。

実際の攻撃シナリオと対策を理解することで、セキュリティの重要性が深まります。


🎭 攻撃者の視点

シナリオ1: プランのアップグレード改ざん

正規のレスポンス:
{
  "user_id": "123",
  "plan": "free",
  "features": {
    "echo": true,
    "advancedEcho": false
  },
  "signature": "MEUCIQDz7..."
}

攻撃者の試み:
{
  "user_id": "123",
  "plan": "premium",  ← 改ざん!
  "features": {
    "echo": true,
    "advancedEcho": true  ← 改ざん!
  },
  "signature": "MEUCIQDz7..."  ← 元の署名のまま
}

結果: ❌ 署名検証失敗!

シナリオ2: 署名の再計算を試みる

攻撃者: 「署名を自分で作り直せばいいのでは?」

必要なもの:
  ✅ データ(ある)
  ❌ 秘密鍵(ない!)

→ 署名を作れない
→ 攻撃失敗

シナリオ3: 過去の署名を再利用

攻撃者: 「以前のpremiumレスポンスを保存しておいて、それを使えば?」

{
  "user_id": "123",
  "plan": "premium",
  "timestamp": 1699564800,  ← 古い!
  "signature": "(過去の正しい署名)"
}

検証側の対策:
  タイムスタンプをチェック
  → 5分以上古い
  → リプレイ攻撃と判断
  → 拒否!

🔐 なぜ改ざんを検知できるのか?

数学的な仕組み

署名生成(サーバー側):
  signature = ECDSA_Sign(
    SHA256(data),
    private_key
  )

署名検証(クライアント側):
  isValid = ECDSA_Verify(
    SHA256(data),
    signature,
    public_key
  )

ポイント:
  データが1bitでも変わる
  → SHA256のハッシュ値が全く変わる
  → 署名検証が失敗する

ハッシュ関数の雪崩効果

元のデータ:
  "plan": "free"
  SHA256: a3f8d2e1b4c7...

改ざん後:
  "plan": "premium"
  SHA256: 9x2k5m8n1p4q...  ← 完全に異なる!

たった1文字の変更でも
ハッシュ値は全く別物になる

🛡️ 多層防御

Layer 1: HTTPS/TLS

通信の暗号化:
  盗聴防止
  中間者攻撃防止

しかし:
  クライアント側で復号化される
  → メモリ上では平文
  → ここで改ざんされる可能性

Layer 2: デジタル署名

HTTPSで守られた後も:
  クライアント側で署名検証
  → アプリ内部での改ざんを検知

例:
  メモリハックツールで
  "free" → "premium" に変更

  → 署名検証で弾かれる

Layer 3: タイムスタンプ

リプレイ攻撃対策:
  過去の正しいレスポンスを
  再利用されることを防ぐ

実装:
  timestamp: 1699564800
  maxAge: 300000 (5分)

  if (now - timestamp > maxAge) {
    reject();
  }

Layer 4: ノンス(Nonce)

一度だけ使える値:
  nonce: "random-value-xyz123"

サーバー側:
  使用済みnonceをメモリに記録
  → 同じnonceの再利用を拒否

実装例:
  const usedNonces = new Set();

  if (usedNonces.has(nonce)) {
    throw new Error('リプレイ攻撃検知');
  }

  usedNonces.add(nonce);

🚨 実際の攻撃手法と対策

攻撃1: Man-in-the-Middle(中間者攻撃)

攻撃:
  クライアント ←→ 攻撃者 ←→ サーバー
                  ↑
              通信を傍受・改ざん

対策:
  ✅ HTTPS/TLS 1.3
  ✅ 証明書のピンニング
  ✅ HSTS ヘッダー

攻撃2: SQL Injection

攻撃:
  email: "admin' OR '1'='1"

対策:
  ✅ プリペアドステートメント
  ✅ 入力バリデーション
  ✅ ORM の使用

攻撃3: Brute Force(総当たり)

攻撃:
  パスワードを片っ端から試す

対策:
  ✅ レートリミット
  ✅ アカウントロック
  ✅ CAPTCHA
  ✅ 2要素認証

✅ セキュリティチェックリスト

通信レベル:
  □ HTTPS/TLS 1.3 の使用
  □ 証明書の検証
  □ HSTS ヘッダー

認証レベル:
  □ 強力なパスワードポリシー
  □ パスワードのハッシュ化(bcrypt)
  □ JWT の署名検証
  □ タイムスタンプの検証

API レベル:
  □ レートリミット
  □ 入力バリデーション
  □ SQL インジェクション対策
  □ XSS 対策

アプリケーションレベル:
  □ 秘密鍵の安全な保管
  □ エラーメッセージの適切な設計
  □ ログの記録
  □ 異常検知

🌟 まとめ

セキュリティ基礎編で学んだこと:

Day 5: 暗号化の基礎

  • 対称鍵と非対称鍵
  • ハイブリッド暗号化

Day 6: ECDSA P-256

  • 楕円曲線暗号
  • RSA との比較

Day 7: JWT

  • Header.Payload.Signature
  • Stateless 認証

Day 8: 署名検証

  • 実装方法
  • エラーハンドリング

Day 9: 改ざん防止(今日)

  • 攻撃シナリオ
  • 多層防御
  • セキュリティチェックリスト

💡 次回予告

Day 10: クライアント・サーバーアーキテクチャ

システムアーキテクチャ編に突入!

  • 全体のシステム構成
  • 通信フロー
  • シーケンス図で理解する

お楽しみに!


前回: Day 8: 署名検証の実装
次回: Day 10: クライアント・サーバーアーキテクチャ

Happy Learning! 🎉

0
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
0
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?