security-audit について
security-auditは、一般的なアプリケーションやインフラのリスクを対象とするコードセキュリティレビュー用スキルです。秘密情報、インジェクション、アクセス制御、データ漏えい、依存関係、技術スタック固有の確認項目とコマンド例を示します。
主な機能
- 01秘密情報と認証情報のスキャン
- 02インジェクションと入力検証の確認
- 03認証と認可のレビュー
- 04データ漏えいと暗号化の確認
- 05依存関係とHTTPヘッダーの確認
- 06フレームワーク別レビュー指針
活用シーン
- 01コードベースの認証情報漏えいを監査
- 02APIコードのインジェクションやアクセス制御を確認
- 03アプリ設定と依存関係を点検
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ aakash-dhar/ claude-skills --skill security-auditインストール後、Claude Code で/security-auditを入力して読み込まれたか確認します。
詳細
セキュリティ監査スキル
コードのセキュリティを監査するときは、この体系的な手順に従ってください。すべての検出事項を重大なものとして扱ってください。脆弱性が1つあるだけで、システム全体が侵害される可能性があります。
1. シークレットと認証情報
コードベース全体をスキャンして、公開されているシークレットを探します。
- ソースコードにハードコードされた API キー、トークン、パスワード
- Git にコミットされた設定ファイル内のシークレット(.env、config.json、settings.py)
- ログ内のシークレット — console.log、logger.info などで出力される機密データ
- エラーメッセージ内のシークレット — 内部情報が漏れるスタックトレースやエラーレスポンス
- コメント内のシークレット — TODO やコメントアウトされたコードに残された古い認証情報
- Git 履歴内のシークレット — シークレットがコミット後に削除されていないか確認します(履歴には残っています)
確認コマンド:
# Search for common secret patterns
grep -rn "password\|secret\|api_key\|apikey\|token\|private_key\|AWS_SECRET\|DATABASE_URL" --include="*.ts" --include="*.js" --include="*.py" --include="*.env" --include="*.json" --include="*.yaml" --include="*.yml" .
# Check for .env files committed
git ls-files | grep -i "\.env"
# Check git history for secrets
git log --all --diff-filter=D -- "*.env" "*.pem" "*.key"
確認事項:
.gitignoreが設定されており、.env、*.pem、*.key、*.p12が含まれていますか?- シークレットはファイルではなく、環境変数またはボールトから読み込まれていますか?
- 実際のシークレットではなく、プレースホルダー値を使った
.env.exampleがありますか?
2. インジェクション攻撃
SQL インジェクション
// 🔴 VULNERABLE — string concatenation in query
const user = await db.query(`SELECT * FROM users WHERE id = '${req.params.id}'`);
// ✅ SAFE — parameterized query
const user = await db.query('SELECT * FROM users WHERE id = $1', [req.params.id]);
NoSQL インジェクション
// 🔴 VULNERABLE — user input directly in query object
const user = await User.find({ username: req.body.username });
// ✅ SAFE — explicitly cast to string
const user = await User.find({ username: String(req.body.username) });
コマンドインジェクション
// 🔴 VULNERABLE — user input in shell command
exec(`convert ${req.body.filename} output.png`);
// ✅ SAFE — use execFile with arguments array
execFile('convert', [sanitizedFilename, 'output.png']);
XSS(クロスサイトスクリプティング)
// 🔴 VULNERABLE — unsanitized HTML rendering
element.innerHTML = userInput;
// React: dangerouslySetInnerHTML={{ __html: userInput }}
// ✅ SAFE — use textContent or sanitize
element.textContent = userInput;
// React: use DOMPurify.sanitize() before dangerouslySetInnerHTML
パストラバーサル
// 🔴 VULNERABLE — user controls file path
const file = fs.readFileSync(`./uploads/${req.params.filename}`);
// ✅ SAFE — resolve and validate path stays within allowed directory
const safePath = path.resolve('./uploads', req.params.filename);
if (!safePath.startsWith(path.resolve('./uploads'))) throw new Error('Invalid path');
テンプレートインジェクション
- ユーザー入力がテンプレートエンジン(Jinja2、EJS、Handlebars)に直接渡されていないか確認します
- 自動エスケープが有効になっていることを確認します
3. 認証と認可
認証の不備
- パスワード要件が弱い — 最小文字数、複雑さ、漏えいチェックがない
- ログインエンドポイントにレート制限がない(ブルートフォース攻撃のリスク)
- ログイン試行失敗後のアカウントロックアウトがない
- パスワードの保存方法が安全でない — 平文、MD5、SHA1(適切なコスト設定で bcrypt/argon2 を使用してください)
- 機密性の高い操作で MFA がない
- URL 内のセッショントークン — トークンはヘッダーまたは httpOnly Cookie に保存してください
- セッションの有効期限がない — 期限切れにならないトークン
認可の不備
- 認可チェックがない — ユーザー権限を確認せずにエンドポイントへアクセスできる
- IDOR(安全でない直接オブジェクト参照) — ID を変更して他のユーザーのデータにアクセスできる
- 権限昇格 — 一般ユーザーが管理者用エンドポイントにアクセスできる
- リソース所有者のチェックがない — ユーザー A がユーザー B のデータを変更できる
// 🔴 VULNERABLE — IDOR: no ownership check
app.get('/api/orders/:id', async (req, res) => {
const order = await Order.findById(req.params.id);
res.json(order);
});
// ✅ SAFE — verify ownership
app.get('/api/orders/:id', async (req, res) => {
const order = await Order.findById(req.params.id);
if (order.userId !== req.user.id) return res.status(403).json({ error: 'Forbidden' });
res.json(order);
});
4. データ漏えい
- API レスポンス内の機密データ — パスワード、トークン、SSN、クレジットカード番号全桁を返している
- 本番環境で詳細すぎるエラーメッセージ — スタックトレース、データベースの詳細、内部パス
- フィールドのフィルタリングがない — 特定のフィールドではなくデータベースオブジェクト全体を返している
- クライアント側ストレージ内の機密データ — localStorage 内のトークン(httpOnly Cookie を使用してください)
- ログ内の PII — 氏名、メールアドレス、IP アドレスがマスキングされずに記録されている
- データ暗号化がない — 機密データが保存時に暗号化されていない
- CORS の設定ミス — 認証が必要なエンドポイントで
Access-Control-Allow-Origin: *を設定している
// 🔴 VULNERABLE — leaking sensitive fields
res.json(user);
// ✅ SAFE — explicit field selection
res.json({
id: user.id,
name: user.name,
email: user.email,
});
5. 入力検証
- 検証がない — リクエストボディ、パラメーター、クエリー文字列をチェックしていない
- 型の混同 — 数値を想定しているのに文字列を受け入れている
- 長さ制限がない — DoS を引き起こす可能性がある、上限のない入力
- ファイルアップロードの検証がない — ファイルの種類、サイズ、内容をチェックしていない
- 正規表現 DoS(ReDoS) — 悪意のある入力による壊滅的なバックトラッキング
- Content-Type の検証がない — 想定外の Content-Type を受け入れている
確認事項:
- 検証ライブラリ(Zod、Joi、class-validator、Pydantic)を使用していますか?
- すべての API エンドポイントで、処理前に入力を検証していますか?
- ファイルアップロードは種類とサイズが制限され、マルウェアスキャンが実施されていますか?
6. 依存関係
次のチェックを実行します:
# Node.js
npm audit
# or
npx better-npm-audit audit
# Python
pip audit
# or
safety check
# Check for outdated packages
npm outdated
pip list --outdated
確認項目:
- 依存関係に既知の CVE がある
- 既知の脆弱性がある古いパッケージ
- メンテナンスが放棄されたパッケージ — 2年以上更新されていない
- タイポスクワッティングのリスク — パッケージ名が正しいことを確認します
- 過剰な権限 — 必要以上のアクセスを要求するパッケージ
- ロックファイルの有無 — package-lock.json または yarn.lock がコミットされている
7. HTTP セキュリティヘッダー
次のヘッダーが設定されているか確認します。
Content-Security-Policy— XSS とデータインジェクションを防止しますStrict-Transport-Security— HTTPS を強制しますX-Content-Type-Options: nosniff— MIME タイプの推測を防止しますX-Frame-Options: DENY— クリックジャッキングを防止しますReferrer-Policy— リファラー情報を制御しますPermissions-Policy— ブラウザー機能を制限します
# Check response headers
curl -I https://your-app.com
8. 暗号化
- 脆弱なハッシュ化 — パスワードに MD5 または SHA1 を使用している(bcrypt、scrypt、または argon2 を使用してください)
- 脆弱な暗号化 — DES、RC4、ECB モードを使用している(AES-256-GCM を使用してください)
- 暗号化キーのハードコード — キーは環境変数またはボールトに保存する必要があります
- TLS の欠如 — 機密データに HTTP 接続を使用している
- 脆弱な JWT —
alg: noneを使用している、または短いシークレットで HS256 を使用している - 予測可能な乱数値 — トークンに Math.random() を使用している(crypto.randomBytes を使用してください)
// 🔴 VULNERABLE — predictable token
const token = Math.random().toString(36);
// ✅ SAFE — cryptographically secure
const token = crypto.randomBytes(32).toString('hex');
9. インフラストラクチャと設定
- 本番環境でのデバッグモード — 詳細なエラー、スタックトレース、デバッグエンドポイントが有効になっている
- デフォルトの認証情報 — admin/admin、root/root が引き続き有効になっている
- 不要なポートの開放 — データベースのポートがインターネットに公開されている
- レート制限の欠如 — DoS への防御がない
- リクエストサイズ制限の欠如 — 大きなペイロードによって OOM が発生する
- 安全でない CORS — 認証済みエンドポイントでワイルドカードオリジンを使用している
- CSRF 対策の欠如 — 状態を変更するエンドポイントに CSRF トークンがない
10. スタック固有のチェック
Node.js / Express
- helmet ミドルウェアがインストールされ、設定されていることを確認します
- express.json() にサイズ制限が設定されていることを確認します:
express.json({ limit: '10kb' }) - Cookie の設定を確認します:httpOnly、secure、sameSite
- オブジェクトのマージでプロトタイプ汚染が発生しないか確認します(lodash.merge、ユーザー入力を用いた Object.assign)
- child_process の呼び出しで、すべての入力がサニタイズされることを確認します
- 認証エンドポイントに express-rate-limit が適用されていることを確認します
- イベントエミッターのメモリリーク(removeListener の呼び出し漏れ)がないか確認します
- ユーザー入力に対して
eval()、Function()、またはvm.runInNewContext()が使用されていないことを確認します
Python / Django
- 本番環境の設定で
DEBUG = Falseになっていることを確認します ALLOWED_HOSTSが['*']になっていないことを確認します- CSRF ミドルウェアが有効になっていることを確認します
- パラメーター化されていない raw SQL クエリがないか確認します
SECRET_KEYがハードコードされず、環境から読み込まれていることを確認します- ユーザー入力の pickle デシリアライズ(RCE のリスク)がないか確認します
- django-cors-headers が特定のオリジンを使って設定されていることを確認します
- 保護対象のすべてのビューに
@login_requiredまたは権限クラスが設定されていることを確認します - 安全でない YAML の読み込み(
Loader=SafeLoaderを指定しないyaml.load())がないか確認します - 本番環境で
SECURE_SSL_REDIRECT、SESSION_COOKIE_SECURE、CSRF_COOKIE_SECUREが True になっていることを確認します
Python / Flask
app.secret_keyがハードコードされていないことを確認します- 保護対象のルートに
@login_requiredデコレーターが設定されていない箇所がないか確認します - Jinja2 の自動エスケープが有効になっていることを確認します(Flask ではデフォルトで有効ですが、カスタムテンプレートを確認してください)
- セキュリティヘッダーの設定に
flask-talismanなどが使われていることを確認します - 認証エンドポイントと機密性の高いエンドポイントに
flask-limiterが適用されていることを確認します - 安全でないファイルアップロード(werkzeug の
secure_filename()の使用漏れ)がないか確認します
React / Next.js
- サニタイズされていない入力に対して
dangerouslySetInnerHTMLが使われていないか確認します - トークンが localStorage に保存されていないことを確認します(httpOnly Cookie を使用してください)
- クライアント側のコードやバンドルに機密データが含まれていないか確認します
- 環境変数で
NEXT_PUBLIC_接頭辞を使っているのが、機密性のない値のみであることを確認します - URL パラメーターを使ったオープンリダイレクトがないか確認します
- API ルートに適切な認証ミドルウェアが設定されていることを確認します
- Server Actions で入力が検証され、認可がチェックされていることを確認します
getServerSidePropsの機密データがpagePropsに漏えいしていないか確認しますnext.config.jsに適切なセキュリティヘッダーが設定されていることを確認します- 本番環境でソースマップが公開されていないか確認します
Vue / Nuxt
- サニタイズされていないユーザー入力に対する
v-htmlの使用を確認します - トークンが localStorage に保存されていないことを確認します
nuxt.configに公開されているランタイム設定のシークレットがないか確認します- サーバーミドルウェアに認証チェックがあることを確認します
useAsyncDataまたはuseFetchを介して、サーバーからクライアントに機密データが漏れていないか確認します
Ruby on Rails
- 本番環境で
config.force_ssl = trueが設定されていることを確認します - ユーザー提供コンテンツに対する
html_safeまたはrawの使用を確認します protect_from_forgeryが有効になっていることを確認します- マスアサインメントの脆弱性(
strong_parametersの不足)がないか確認します has_secure_passwordが bcrypt を使用していることを確認します- ユーザー入力に対する安全でない
send()またはconstantize()の使用を確認します config.filter_parametersに機密フィールドが含まれていることを確認します
Go
- クエリで使用される
fmt.Sprintfに SQL インジェクションの脆弱性がないか確認します(パラメーター化クエリを使用してください) - TLS 設定で TLS 1.2 以上が使用されていることを確認します
http.ServeFileまたはos.Openにパストラバーサルの脆弱性がないか確認します- 適切なエラー処理が行われていることを確認します(エラーレスポンスに機密データを含めないでください)
- 共有状態における競合状態(ミューテックスの不足)がないか確認します
- セキュリティ上重要な値には
math/randではなくcrypto/randが使用されていることを確認します - パニックを引き起こす可能性のある、チェックされていない型アサーションがないか確認します
Java / Spring Boot
- Spring Security が設定されており、機密性の高いエンドポイントで
permitAll()が使用されていないことを確認します - 文字列連結を使った
@Queryアノテーションに SQL インジェクションの脆弱性がないか確認します - CSRF 保護が有効になっていることを確認します(Spring Security のデフォルト設定)
- デシリアライゼーションの脆弱性(Jackson、Java シリアライゼーション)がないか確認します
- リクエスト本文のパラメーターに
@Validアノテーションが付いていることを確認します application.propertiesまたはapplication.ymlにハードコードされた認証情報がないか確認します- actuator エンドポイントが保護され、一般公開されていないことを確認します
- 依存関係に Log4j/Log4Shell の脆弱性がないか確認します
PHP / Laravel
- 本番環境の
.envでAPP_DEBUG=falseが設定されていることを確認します - パラメーターバインディングなしで実行される生の SQL クエリがないか確認します
- すべての POST/PUT/DELETE ルートに CSRF ミドルウェアが適用されていることを確認します
- ユーザー入力に対する
eval()、exec()、system()の使用を確認します - ファイルアップロードに検証ルール(MIME タイプ、最大サイズ)が適用されていることを確認します
- 機密性の高いルートが
Auth::check()またはミドルウェアのガードによって保護されていることを確認します $fillableまたは$guardedによってmass assignmentが保護されていることを確認します- ユーザー入力に対する
{!! !!}を使った安全でない Blade レンダリングがないか確認します
モバイル(React Native / Flutter)
- AsyncStorage/SharedPreferences に機密データが保存されていないか確認します(暗号化ストレージを使用してください)
- API キーがアプリのバンドルに埋め込まれていないことを確認します
- 機密性の高い API 呼び出しで証明書ピンニングが行われていることを確認します
- ディープリンクハンドラーが、ナビゲーションの前に入力を検証していることを確認します
- アプリのログ(adb logcat / Console.app で表示可能)に機密データが含まれていないか確認します
- 生体認証がサーバー側で適切に検証されていることを確認します
- 信頼されていないコンテンツに対して JavaScript を有効にするなど、安全でない WebView 設定がないか確認します
決済セキュリティ
- PCI DSS のコンプライアンス要件を満たしていることを確認します
- クレジットカード番号の全桁が保存またはログに記録されないことを確認します
- 決済処理でトークナイゼーションが使用されていることを確認します
- Webhook エンドポイントが署名を検証していることを確認します
- 返金エンドポイントに適切な認可とレート制限が設定されていることを確認します
- 決済金額がサーバー側で検証されていることを確認します(クライアントからの値を信頼しないでください)
- 決済確認ページの URL に取引の詳細が露出していないことを確認します
- 決済処理に競合状態(多重請求のリスク)がないか確認します
AWS / クラウドインフラストラクチャ
- 過度に許可範囲の広い IAM ポリシー(
"Action": "*"、"Resource": "*")がないか確認します - S3 バケットが一般公開されていないことを確認します
- 暗号化されていない RDS インスタンスまたは EBS ボリュームがないか確認します
- セキュリティグループで機密性の高いポートへの 0.0.0.0/0 からのアクセスが許可されていないことを確認します
- ハードコードされた AWS 認証情報がないか確認します(代わりに IAM ロールを使用してください)
- CloudTrail のロギングが有効になっていることを確認します
- 機密性の高いサービスを実行している EC2 インスタンスが一般公開されていないか確認します
- シークレットが AWS Secrets Manager または Parameter Store に保存されていることを確認します
Docker/コンテナー
- root として実行されているコンテナーを確認します
- ベースイメージが信頼できるソースのものであり、特定のバージョンに固定されていることを確認します
- Docker イメージにシークレットが組み込まれていないか確認します(ビルドシークレットまたは実行時環境変数を使用してください)
.dockerignoreで.env、.git、node_modulesが除外されていることを確認します- 本番用イメージに不要なパッケージがインストールされていないか確認します
- ヘルスチェックが設定されていることを確認します
- 公開すべきでないポートが公開されていないか確認します
出力形式
見つかった脆弱性ごとに、次の形式で記載します。
[重大度] カテゴリー — ファイル:行
- 脆弱性:問題の内容
- リスク:攻撃者がこれを利用して何を実行できるか
- 実証:悪用方法(チーム内での理解を目的とします)
- 修正:問題を解決するための具体的なコード変更
- 参考情報:該当する場合は CWE または OWASP のリンク
// vulnerable code
...
// fixed code
...
重大度のレベル:
- 🔴 CRITICAL — 現実に悪用可能です。データ侵害、RCE、またはシステム全体の侵害につながります。直ちに修正してください。
- 🟠 HIGH — ある程度の労力をかければ悪用可能です。重大なデータ漏えいや権限昇格につながります。次回のデプロイ前に修正してください。
- 🟡 MEDIUM — 悪用には特定の条件が必要です。現在のスプリント中に修正してください。
- 🟢 LOW — 軽微な問題、または多層防御の改善です。都合のよいときに修正してください。
まとめ
すべての監査の最後に、次の項目を記載してください。
- リスク評価 — 全体的なセキュリティ態勢(Critical/High/Medium/Low リスク)
- 重大な指摘事項の数 — 直ちに対応が必要な問題の数
- 最も危険な問題トップ 3 — 悪用の容易さと影響度に基づく順位
- すぐにできる改善 — 30 分未満で実施でき、リスクを大幅に低減できる修正
- 推奨事項 — WAF、セキュリティヘッダー、CI での依存関係スキャンなど、中長期的な改善
- 適切に実施できていること — 維持すべき、すでに導入されているセキュリティ対策
コメント
Markdown 対応