static-application-security-testing について
static-application-security-testingは、アプリケーションを実行せずにソースコードリポジトリの脆弱性を調べるエージェント向けスキルです。言語に応じたSASTツールを選び、結果を精査し、レポートやCI連携を設定します。
主な機能
- 01言語とフレームワークの検出
- 02適切なSASTツールの選定
- 03ソースコードの静的スキャン
- 04検出結果の分類と重複排除
- 05修正案を含むレポート作成
- 06CIパイプライン連携の設定
活用シーン
- 01リポジトリのインジェクション脆弱性確認
- 02スキャン結果の優先順位付けと確認
- 03CI向けSARIF結果の出力
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ seb1n/ awesome-ai-agent-skills --skill static-application-security-testingインストール後、Claude Code で/static-application-security-testingを入力して読み込まれたか確認します。
詳細
静的アプリケーションセキュリティテスト
このスキルを使うと、エージェントはアプリケーションを実行せずに、ソースコードリポジトリに対して静的アプリケーションセキュリティテスト(SAST)を実施し、セキュリティの脆弱性を検出できます。エージェントはプロジェクトの言語に応じて適切な解析ツールを選択し、関連するルールセットでスキャンを実行し、検出結果をトリアージして真陽性と偽陽性を分類し、CI/CD パイプラインに結果を統合します。SAST を利用すると、SQL インジェクション、クロスサイトスクリプティング、ハードコードされたシークレット、安全でないデシリアライゼーション、暗号の誤用といった問題を、開発ライフサイクルの早い段階で検出できます。
ワークフロー
-
言語とフレームワークの検出 — リポジトリを解析し、使用されている主要な言語(Python、JavaScript、Java、Go、C# など)とフレームワークを特定します。これにより、適用できる SAST ツールとルールセットが決まります。
.semgrep.yml、codeqlクエリパック、.bandit設定ファイルなど、既存のツール設定を確認します。 -
SAST ツールの選択と設定 — 検出した技術スタックに適したツールを選択します。複数言語のパターンマッチングには Semgrep、深い意味解析には CodeQL、Python 固有のチェックには Bandit、JavaScript/TypeScript には ESLint のセキュリティプラグインを使用します。組み込みのセキュリティルールセットと、プロジェクト固有のカスタムルールを読み込みます。
-
静的解析の実行 — 選択したツールをコードベースに対して実行します。脆弱性の種類、該当するファイルと行番号、重大度、CWE 識別子、問題の説明など、すべての検出結果を記録します。大規模なコードベースでは、複数のツールによるスキャンを並行して実行します。
-
検出結果のトリアージと重複排除 — 複数のツールの結果を統合し、同じ問題の重複検出を取り除いたうえで、検出結果を真陽性、偽陽性、要レビューに分類します。検出された SQL 文字列が実際にデータベースドライバーに渡されるかを確認するなど、コンテキストを考慮した解析によってノイズを減らします。
-
修正案付きレポートの作成 — 重大度とカテゴリごとに整理した、構造化された検出結果レポートを作成します。脆弱なコードの抜粋、リスクの説明、修正後のコードを含む修正案、および関連する CWE 項目と OWASP カテゴリへの参照を記載します。
-
CI パイプラインへの統合 — すべてのプルリクエスト、または保護されたブランチへのプッシュごとにスキャンが実行されるよう設定します。重大または高重大度の検出結果が追加された場合にマージをブロックする品質ゲートを設定します。GitHub Code Scanning、GitLab SAST、SonarQube との統合には、SARIF 形式で結果を出力します。
対応技術
- 複数言語:Semgrep(Python、JS/TS、Java、Go、Ruby、C#、PHP、Kotlin、Rust)
- 深い意味解析:CodeQL(Java、JavaScript、Python、C/C++、C#、Go、Ruby)
- Python:Bandit、Pylint のセキュリティチェッカー
- JavaScript/TypeScript:ESLint(eslint-plugin-security、eslint-plugin-no-secrets)、njsscan
- Java:Find Security Bugs プラグインを備えた SpotBugs、PMD
- 出力形式:SARIF、JSON、JUnit XML、Markdown
- CI プラットフォーム:GitHub Actions、GitLab CI、Jenkins、Azure DevOps
使用方法
エージェントにソースコードリポジトリのパスを指定します。必要に応じて、対象言語、カスタムルールファイル、またはパイプライン統合用の CI プラットフォームも指定できます。エージェントは適切な SAST ツールを実行し、優先順位を付けた検出結果レポートを提示します。
プロンプトの例:
Run SAST on the Python application in /app using Semgrep and Bandit. Flag any SQL injection, hardcoded secrets, and insecure deserialization. Output results in SARIF format for GitHub Code Scanning.
例
例 1:Python Flask アプリケーションの Semgrep スキャン
コマンド:
semgrep scan --config=p/owasp-top-ten --config=p/python --json --output=semgrep-results.json /app
検出結果(抜粋):
┌─────────────────────────────────────────────────────────────────┐
│ python.flask.security.injection.sql-injection-with-format-string │
│ Severity: ERROR │ CWE-89 │ OWASP A03:2021 │
├─────────────────────────────────────────────────────────────────┤
│ /app/routes/users.py:42 │
│ │
│ 40│ def search_users(name): │
│ 41│ query = f"SELECT * FROM users WHERE name = '{name}'"│
│ 42│ result = db.execute(query) │
│ │
│ Fix: Use parameterized queries instead of string formatting. │
├─────────────────────────────────────────────────────────────────┤
│ python.lang.security.audit.hardcoded-password │
│ Severity: WARNING │ CWE-798 │ OWASP A07:2021 │
├─────────────────────────────────────────────────────────────────┤
│ /app/config.py:11 │
│ │
│ 10│ class Config: │
│ 11│ DB_PASSWORD = "SuperSecret123!" │
│ 12│ JWT_SECRET = "my-jwt-secret" │
│ │
│ Fix: Load secrets from environment variables or a secrets │
│ manager, never hardcode them in source files. │
└─────────────────────────────────────────────────────────────────┘
SQL インジェクションの検出結果を修正したコード:
# BEFORE — vulnerable to SQL injection
def search_users(name):
query = f"SELECT * FROM users WHERE name = '{name}'"
result = db.execute(query)
return result
# AFTER — parameterized query
def search_users(name):
query = "SELECT * FROM users WHERE name = :name"
result = db.execute(text(query), {"name": name})
return result
例 2:Java の安全でないデシリアライゼーションを検出する CodeQL クエリ
カスタム CodeQL クエリ(insecure-deserialization.ql):
/**
* @name Insecure deserialization of untrusted data
* @description Deserializing data from an untrusted source without validation
* can lead to remote code execution.
* @kind path-problem
* @problem.severity error
* @id java/insecure-deserialization
* @tags security
* cwe-502
* owasp-a08
*/
import java
import semmle.code.java.dataflow.TaintTracking
import semmle.code.java.security.UnsafeDeserializationQuery
from UnsafeDeserializationConfig config, DataFlow::PathNode source, DataFlow::PathNode sink
where config.hasFlowPath(source, sink)
select sink.getNode(), source, sink,
"Untrusted data from $@ is deserialized here without validation.", source.getNode(),
"user-controlled input"
クエリの実行:
codeql database create java-db --language=java --source-root=/app
codeql database analyze java-db insecure-deserialization.ql --format=sarif-latest --output=codeql-results.sarif
検出結果の例:
/app/src/main/java/com/example/api/ImportController.java:35
ObjectInputStream ois = new ObjectInputStream(request.getInputStream());
Object obj = ois.readObject(); // CWE-502: untrusted deserialization
Fix: Replace ObjectInputStream with a safe alternative like JSON deserialization
with explicit type binding, or use an allowlist-based ObjectInputFilter.
ベストプラクティス
- シフトレフト — すべてのプルリクエストでスキャンする — コードレビュー中に脆弱性を発見するほうが、本番環境で発見するよりも10〜100倍低コストです。保護対象のすべてのブランチで、SASTを必須のCIチェックとして設定してください。
- 誤検知を減らすためにルールを調整する — すべてのルールを有効にするのではなく、厳選されたセキュリティルールセット(例:Semgrep
p/owasp-top-ten)から始めてください。誤検知と確認できた場合は、根拠を文書化して抑制ルールを追加してください。 - 複数のツールを組み合わせる — すべてを検出できる単一のSASTツールはありません。パターンベースのツール(Semgrep)とセマンティック解析ツール(CodeQL)を組み合わせて、より広範囲をカバーしてください。ツールごとに得意分野は異なります。
- コードベースに合わせてカスタムルールを作成する — データベースクエリがすべてサニタイズ用ラッパー関数を経由することを確認するなど、内部のセキュリティパターンを徹底するため、プロジェクト固有のSemgrepまたはCodeQLルールを記述してください。
- 統一的なレポートにはSARIFを使用する — Static Analysis Results Interchange Formatは、GitHub、GitLab、Azure DevOps、SonarQubeでサポートされているため、検出に使用したツールにかかわらず、すべてのSASTの検出結果を単一のダッシュボードで確認できます。
安全上の境界
- ユーザーが所有するシステム、または評価する明示的な許可を得ているシステムのみを対象とし、テスト前に承認済みの範囲を記録してください。
- 受動的な調査、または読み取り専用の検査から始めてください。アクティブスキャン、エクスプロイト、負荷の生成、または影響を伴う修正を行う前に、明示的な承認を得てください。
- シークレットを公開したり、無関係なデータを抽出したり、本番環境の制御を弱めたり、承認済みの対象範囲を超えたりしないでください。
- 証拠を保全し、影響を最小限に抑え、不安定な状態が発生した場合は停止してください。重大な変更には、ロールバックまたは封じ込めの手順を必ず提示してください。
エッジケース
- 生成コードまたはベンダーコード — SASTツールは、自動生成されたprotobufスタブ、ベンダー依存関係、またはマイグレーションファイルの問題を検出することがあります。ノイズを避けるため、
.semgrepignoreまたはCodeQLのパスフィルターを使って、これらのパスをスキャン対象から除外してください。 - テンプレート言語とDSL — Jinja2テンプレート、ERB、JSXなどのテンプレート言語は、すべてのSASTツールで完全に解析できるとは限りません。テンプレート構文に対応した、ツール固有のプラグインまたは補助的なスキャナーを使用してください。
- テストコードでの誤検知 — テストファイルには、意図的に安全でないパターン(例:ハードコードされたテスト用認証情報、テストセットアップ用の生のSQL)が含まれることがよくあります。テストディレクトリには、別のルールセットまたは重大度のしきい値を設定してください。
- スキャンに時間がかかる大規模モノレポ — 100万行のモノレポ全体をCodeQLで解析すると、1時間以上かかることがあります。増分解析を使用し、プルリクエストでは変更されたファイルのみをスキャンして、全体スキャンは夜間に実行してください。
- 過去のコミットに含まれるシークレット — SASTツールは現在の作業ツリーをスキャンし、Gitの履歴はスキャンしません。GitleaksやTruffleHogなどのシークレットスキャンツールをSASTと併用し、過去のリビジョンでコミットされ、Gitログにまだ残っている認証情報を検出してください。