🎄 科学と神々株式会社アドベントカレンダー 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! 🎉