アンチパターン⑫「パスワード平文保存」
基本的なセキュリティ違反
パスワードの平文保存は、最も基本的なセキュリティ違反の一つです。
CodeRabbit 2025調査:
AI生成コードは不適切なパスワード処理の可能性が 1.88倍
AIが生成するコードは、パスワードを安全に処理しないことが多いのです。
【要注意】典型的な危険コードパターン
AIが生成しがちな危険なコードを見てみましょう。
危険なコード:
// ❌ 平文保存
app.post('/register', async (req, res) => {
const { email, password } = req.body;
await db.users.insert({
email: email,
password: password // 平文!
});
res.json({ success: true });
});
// ❌ 弱いハッシュアルゴリズム
const hashedPassword = crypto.createHash('md5').update(password).digest('hex');
const hashedPassword = crypto.createHash('sha1').update(password).digest('hex');
// ❌ ソルトなし
const hashedPassword = crypto.createHash('sha256').update(password).digest('hex');
なぜ危険なのか
平文保存が危険な理由を説明します。
問題1: データベース漏洩時の被害
- データベースが漏洩すると、全パスワードが露出
- 攻撃者はすぐにアカウントを乗っ取れる
問題2: パスワードの使い回し
- ユーザーは同じパスワードを複数サービスで使用
- 1つのサービスからの漏洩が、他のサービスにも影響
問題3: 内部犯行
- データベースにアクセスできる従業員が見れる
- 内部からの攻撃リスク
問題4: ログへの露出
- エラーログにパスワードが記録される可能性
- デバッグ時に平文が表示される
AI生成コードの弱いハッシュ問題:MD5, SHA1
MD5やSHA-1は、パスワードハッシュには不適切です。
理由:
-
計算が速すぎる
- GPUで毎秒数十億回のハッシュ計算可能
- ブルートフォースに弱い
-
レインボーテーブル
- 事前計算されたハッシュテーブルで即座に解読
-
衝突攻撃
- 同じハッシュを持つ別の値を見つけられる
ベンチマーク:
| アルゴリズム | 計算速度 | パスワード解読時間 |
|---|---|---|
| MD5 | 非常に速い | 数秒〜数分 |
| SHA-1 | 速い | 数分〜数時間 |
| bcrypt | 遅い(意図的) | 数年〜数十年 |
実践的な解決策:正しいパスワード処理
パスワードを安全に処理する方法を解説します。
実践的な解決策1: bcryptを使用
const bcrypt = require('bcrypt');
const SALT_ROUNDS = 12; // コストファクター
// ハッシュ化
async function hashPassword(password) {
return await bcrypt.hash(password, SALT_ROUNDS);
}
// 検証
async function verifyPassword(password, hash) {
return await bcrypt.compare(password, hash);
}
// 使用例
app.post('/register', async (req, res) => {
const { email, password } = req.body;
const hashedPassword = await hashPassword(password);
await db.users.insert({
email: email,
password: hashedPassword
});
res.json({ success: true });
});
app.post('/login', async (req, res) => {
const { email, password } = req.body;
const user = await db.users.findByEmail(email);
if (!user) {
return res.status(401).json({ error: 'Invalid credentials' });
}
const isValid = await verifyPassword(password, user.password);
if (!isValid) {
return res.status(401).json({ error: 'Invalid credentials' });
}
// ログイン成功
});
実践的な解決策2: Argon2を使用(より新しい選択肢)
const argon2 = require('argon2');
// ハッシュ化
async function hashPassword(password) {
return await argon2.hash(password, {
type: argon2.argon2id,
memoryCost: 65536,
timeCost: 3,
parallelism: 4
});
}
// 検証
async function verifyPassword(password, hash) {
return await argon2.verify(hash, password);
}
実践的な解決策3: コストファクターの設定
// bcryptのコストファクター
// 高いほど安全だが、処理時間も増加
const SALT_ROUNDS = 12; // 推奨(約250ms)
// 参考値
// 10: 約65ms
// 11: 約130ms
// 12: 約250ms
// 13: 約500ms
// 14: 約1秒
// サーバーの性能に応じて調整
追加のセキュリティ対策
パスワードハッシュ以外の対策も重要です。
ブルートフォース対策
const rateLimit = require('express-rate-limit');
const loginLimiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15分
max: 5, // 5回まで
message: 'Too many login attempts'
});
app.post('/login', loginLimiter, async (req, res) => {
// ...
});
アカウントロックアウト
const MAX_ATTEMPTS = 5;
const LOCKOUT_TIME = 30 * 60 * 1000; // 30分
async function checkLockout(email) {
const attempts = await db.loginAttempts.count(email);
if (attempts >= MAX_ATTEMPTS) {
const lastAttempt = await db.loginAttempts.getLastTime(email);
if (Date.now() - lastAttempt < LOCKOUT_TIME) {
throw new Error('Account locked');
}
}
}
プロンプトによるセキュリティ対策
AIにユーザー認証を依頼する際のプロンプト例です。
良いプロンプト:
ユーザー登録・ログイン機能を実装して:
## パスワード要件
- bcryptでハッシュ化(コストファクター12以上)
- 平文でのパスワード保存禁止
- MD5/SHA-1の使用禁止
- パスワードをログに出力しない
## 追加セキュリティ
- レート制限(5回/15分)
- アカウントロックアウト(5回失敗で30分)
- パスワード強度チェック
実装前チェックリスト
パスワード処理のチェックリストです。
コードレビュー時:
- bcrypt/Argon2を使用しているか
- コストファクターは適切か(12以上推奨)
- 平文でパスワードを保存していないか
- MD5/SHA-1を使用していないか
設定確認:
- パスワードがログに出力されていないか
- レート制限が設定されているか
- アカウントロックアウトがあるか
この事例から学ぶべき教訓と実践ポイント
「パスワード平文保存」から学ぶべきことは以下の通りです。
-
1.88倍の不適切処理
- AI生成コードはパスワード処理が甘い
-
平文保存は絶対禁止
- データベース漏洩で全滅
-
MD5/SHA-1は不適切
- 速すぎてブルートフォースに弱い
-
bcrypt/Argon2を使用
- 意図的に遅い設計
-
追加対策も重要
- レート制限、アカウントロック
まとめ:重要ポイントの振り返り
- AI生成コードは不適切なパスワード処理が 1.88倍 (CodeRabbit)
- 平文保存は絶対禁止
- MD5/SHA-1は使用禁止 (速すぎる)
- 解決策:bcrypt(コスト12以上)またはArgon2
- 追加対策:レート制限、アカウントロック
- プロンプトで パスワード要件を明示
- 教訓:パスワードは必ずハッシュ化せよ