security-hardening について
security-hardeningは、デプロイ前のWebアプリケーションやAPIを保護する開発者向けの実践スキルです。入力検証、インジェクション対策、認証、シークレット管理、依存関係の監査、デプロイチェックリストを扱います。
主な機能
- 01入力検証と出力エンコーディング
- 02SQLインジェクション対策
- 03CSRFとコンテンツセキュリティポリシー
- 04セキュリティヘッダーとレート制限
- 05JWTとシークレット管理の実践
- 06依存関係の監査とデプロイチェックリスト
活用シーン
- 01デプロイ前にAPIをレビューする
- 02インジェクションやXSSのリスクを抑える
- 03認証とレート制限の方針を設定する
- 04CIで依存関係とシークレットを確認する
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ rohitg00/ awesome-claude-code-toolkit --skill security-hardeningインストール後、Claude Code で/security-hardeningを入力して読み込まれたか確認します。
詳細
セキュリティの強化
入力検証
すべての入力を境界で検証します。クライアント側の検証だけを信用しないでください。
import { z } from 'zod';
const CreateUserSchema = z.object({
email: z.string().email().max(255),
name: z.string().min(1).max(100).regex(/^[a-zA-Z\s'-]+$/),
age: z.number().int().min(13).max(150),
});
function createUser(req: Request) {
const result = CreateUserSchema.safeParse(req.body);
if (!result.success) {
return { status: 400, errors: result.error.flatten().fieldErrors };
}
// result.data is typed and validated
}
ルール:
- すべての入力について、型、長さ、形式、範囲を検証する
- 拒否リストより許可リストを使用する(既知の安全な値を受け入れ、それ以外はすべて拒否する)
- ファイルのアップロードを検証する:MIME タイプ、ファイル拡張子、マジックバイトを確認する
- サーバーまたはプロキシのレベルでリクエストボディのサイズを制限する(例:最大 1MB)
出力のエンコード
// Prevent XSS: encode output based on context
// HTML context: use framework auto-escaping (React does this by default)
// Never use dangerouslySetInnerHTML with user input
// URL context: encode parameters
const safeUrl = `/search?q=${encodeURIComponent(userInput)}`;
// JSON context: use JSON.stringify (handles escaping)
const safeJson = JSON.stringify({ query: userInput });
ユーザー入力を使って HTML 文字列を構築しないでください。自動エスケープが有効なテンプレートエンジンを使用してください。
SQL インジェクションの防止
# NEVER do this
cursor.execute(f"SELECT * FROM users WHERE id = {user_id}")
# Always use parameterized queries
cursor.execute("SELECT * FROM users WHERE id = %s", (user_id,))
// NEVER do this
db.query(`SELECT * FROM users WHERE email = '${email}'`);
// Always use parameterized queries
db.query("SELECT * FROM users WHERE email = $1", [email]);
ORM またはクエリビルダーを使用してください。生の SQL を記述する場合は、必ずパラメーター化してください。
CSRF 対策
// Server: generate and validate CSRF tokens
import { randomBytes } from 'crypto';
function generateCsrfToken(): string {
return randomBytes(32).toString('hex');
}
// Middleware: validate on state-changing requests
function csrfMiddleware(req, res, next) {
if (['POST', 'PUT', 'PATCH', 'DELETE'].includes(req.method)) {
const token = req.headers['x-csrf-token'] || req.body._csrf;
if (!timingSafeEqual(token, req.session.csrfToken)) {
return res.status(403).json({ error: 'Invalid CSRF token' });
}
}
next();
}
トークンベースの認証(Bearer トークン)を使用する API では、ブラウザーがトークンを自動送信しないため、CSRF 対策は不要です。
コンテンツセキュリティポリシー
Content-Security-Policy:
default-src 'self';
script-src 'self' 'nonce-{random}';
style-src 'self' 'unsafe-inline';
img-src 'self' data: https:;
font-src 'self';
connect-src 'self' https://api.example.com;
frame-ancestors 'none';
base-uri 'self';
form-action 'self';
厳格な設定から始め、必要に応じて緩和してください。インラインスクリプトには unsafe-inline の代わりに nonce を使用してください。report-uri ディレクティブで違反を報告します。まず Content-Security-Policy-Report-Only でテストしてください。
セキュリティヘッダー
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: camera=(), microphone=(), geolocation=()
すべてのレスポンスにこれらを設定してください。helmet(Node.js)または同等のミドルウェアを使用してください。
レート制限
// Per-user, per-endpoint rate limiting
const rateLimits = {
'POST /auth/login': { window: '15m', max: 5 },
'POST /auth/register': { window: '1h', max: 3 },
'POST /api/*': { window: '1m', max: 60 },
'GET /api/*': { window: '1m', max: 120 },
};
スライディングウィンドウアルゴリズムを使用してください。カウンターは Redis に保存します。Retry-After ヘッダーを付けて 429 を返します。認証エンドポイントには、より厳しい制限を適用してください。
JWT のベストプラクティス
- アクセストークンの有効期限は短く設定します(15 分)
- リフレッシュトークン(7〜30 日)を使用し、httpOnly クッキーに保存します
- マイクロサービスでは RS256(非対称)、モノリスでは HS256(対称)で署名します
- JWT ペイロードに機密データを保存しないでください(Base64 でエンコードされているだけで、暗号化されていません)
- すべてのリクエストで
iss、aud、exp、nbfクレームを検証します - 拒否リスト、または短い有効期限とローテーションにより、トークンの失効を実装します
// Verify JWT with all checks
const payload = jwt.verify(token, publicKey, {
algorithms: ['RS256'],
issuer: 'auth.example.com',
audience: 'api.example.com',
clockTolerance: 30,
});
シークレットの管理
- シークレットをバージョン管理にコミットしないでください(
.envには.gitignoreを使用します) - 実行時のシークレットには環境変数を使用します
- 本番環境ではシークレットマネージャーを使用します(AWS Secrets Manager、HashiCorp Vault、Doppler)
- シークレットを定期的にローテーションします(API キーは最大 90 日)
- 環境ごとに異なるシークレットを使用します(dev/staging/prod)
- CI で漏えいしたシークレットをスキャンします:
trufflehog、gitleaks、git-secrets
# Check for secrets in git history
gitleaks detect --source . --verbose
# Pre-commit hook to prevent secret commits
gitleaks protect --staged
依存関係の監査
# Node.js
npm audit --production
npx better-npm-audit audit --level=high
# Python
pip-audit
safety check
# Go
govulncheck ./...
すべての PR で CI による依存関係の監査を実行します。重大または高リスクの脆弱性がある場合は、マージをブロックします。依存関係のバージョンを固定します。自動 PR(Dependabot、Renovate)を使って、依存関係を毎週更新します。
デプロイ前のチェックリスト
- すべての入力がスキーマ検証で検証されている
- SQL クエリがパラメーター化されている
- セキュリティヘッダーが設定されている
- HSTS によって HTTPS が強制されている
- シークレットがコード内ではなく、外部で管理されている
- 依存関係が監査され、重大な脆弱性がない
- すべての公開エンドポイントにレート制限が適用されている
- 認証トークンに有効期限とローテーションが設定されている
- エラーメッセージから内部の詳細が漏えいしない
- 機密データを含めずに、ログにセキュリティイベントが記録される