LESSON 30分

ストーリー

田中VPoE
Step 1でセキュリティ要件を定義した。ここからはそれを自動で検証する仕組みを作る。まずはSAST — 静的アプリケーションセキュリティテストだ
あなた
SASTは「コードを実行せずにソースコードを解析して脆弱性を見つける」ものですよね
田中VPoE
その通り。SASTはShift Leftの最前線だ。開発者がコードを書いた瞬間、PRを出した瞬間に脆弱性を検出できる。リリース前のゲートレビューを待たずにフィードバックが返る
あなた
ESLintのセキュリティ版のようなイメージですか?
田中VPoE
近い。ただし、ESLintが構文レベルの問題を見つけるのに対し、SASTツールはデータフローを追跡する。ユーザー入力がどこを通ってSQLクエリに到達するか、そのパスに適切なサニタイズがあるかを解析する。これが「汚染解析(Taint Analysis)」だ

SASTの仕組み

解析手法の種類

解析手法概要検出精度速度
パターンマッチング正規表現ベースで危険なパターンを検出低〜中(誤検知多い)高速
AST解析抽象構文木を解析し構文レベルの問題を検出高速
データフロー解析変数の値がどう伝播するかを追跡中〜高中速
汚染解析(Taint Analysis)ユーザー入力(Source)から危険な操作(Sink)への到達パスを追跡低速
制御フロー解析実行パスの分岐を考慮した解析低速

汚染解析の概念

汚染解析(Taint Analysis)の基本:

Source(汚染源): ユーザーからの入力
  ├── req.body
  ├── req.params
  ├── req.query
  ├── req.headers
  └── 環境変数(場合による)

Sink(危険な操作): 汚染データが到達すると危険な箇所
  ├── SQL クエリ実行 → SQLインジェクション
  ├── HTML レンダリング → XSS
  ├── OS コマンド実行 → コマンドインジェクション
  ├── ファイルパス操作 → パストラバーサル
  └── ログ出力 → ログインジェクション

Sanitizer(無害化): 汚染を除去する処理
  ├── パラメータ化クエリ
  ├── HTML エスケープ
  ├── 入力バリデーション
  └── 型変換

判定ロジック:
  Source → (Sanitizerなし) → Sink = 脆弱性あり
  Source → Sanitizer → Sink = 安全

主要なSASTツール

ツール比較

ツール対象言語ライセンス特徴
Semgrep30以上の言語OSS(Community)/ 商用ルールの記述が容易、高速、カスタムルール
SonarQube30以上の言語OSS(Community)/ 商用品質管理と統合、豊富なルール
CodeQLJavaScript, Python, Java, Go等無料(GitHub)GitHub連携が強力、クエリ言語による高度な解析
Snyk Code多言語FreemiumAI支援、IDE統合、修正提案
Checkmarx多言語商用エンタープライズ向け、高い検出精度
BanditPythonOSSPython特化、軽量
ESLint SecurityJavaScript/TypeScriptOSSESLintプラグイン、導入が容易

Semgrepのルール例

# Semgrep ルール: SQLインジェクション検出
rules:
  - id: sql-injection-node
    patterns:
      - pattern: |
          $DB.query(`...${$USER_INPUT}...`)
      - pattern-not: |
          $DB.query(`...${parseInt($USER_INPUT)}...`)
    message: |
      ユーザー入力がSQLクエリに直接埋め込まれています。
      パラメータ化クエリを使用してください。
      要件参照: SEC-INPUT-001
    severity: ERROR
    languages: [typescript, javascript]
    metadata:
      category: security
      cwe: "CWE-89"
      owasp: "A03:2021"
      compliance:
        pci-dss: "6.5.1"
        soc2: "CC7.1"
# Semgrep ルール: ハードコードされたシークレット検出
rules:
  - id: hardcoded-secret
    patterns:
      - pattern: |
          $VAR = "..."
      - metavariable-regex:
          metavariable: $VAR
          regex: ".*(password|secret|api_key|token|credential).*"
      - metavariable-regex:
          metavariable: "$VALUE"
          regex: ".{8,}"
    message: |
      シークレットがハードコードされている可能性があります。
      環境変数またはシークレット管理サービスを使用してください。
      要件参照: SEC-DATA-004
    severity: ERROR
    languages: [typescript, javascript, python]

SASTの導入パターン

段階的導入戦略

フェーズ範囲ルールブロック
Phase 1(1-2週間)新規PRのみCritical脆弱性のみ警告のみ(ブロックしない)
Phase 2(1ヶ月)新規PR + 差分Critical + HighCriticalはブロック
Phase 3(2-3ヶ月)全コードベースCritical + High + MediumCritical + Highはブロック
Phase 4(定常運用)全コードベース + カスタムルール全レベルポリシーに基づきブロック

「最初からすべてをブロックすると開発が止まる。段階的に導入し、開発者がSASTに慣れる時間を作ることが成功の鍵だ」 — 田中VPoE

誤検知(False Positive)への対処

対処法方法適用場面
インラインサプレスコメントで特定行を除外誤検知が明確な場合
ルールチューニングルールのパターンを調整誤検知が頻発する場合
ベースライン設定既存の検出結果を除外し、新規のみ検出レガシーコードベース
除外パス設定テストコード等を除外テストファイルの誤検知
# .semgrepignore の例
# テストファイルは除外
tests/
__tests__/
*.test.ts
*.spec.ts

# 自動生成コードは除外
generated/
node_modules/

SASTのメトリクス

メトリクス定義目標値
検出率(Detection Rate)実際の脆弱性のうちSASTが検出した割合80%以上
誤検知率(False Positive Rate)検出結果のうち実際には脆弱性でない割合20%以下
修正時間(MTTR)検出から修正までの平均時間48時間以内
カバレッジSASTが対象とするコードの割合95%以上
ルール数有効なSASTルールの数言語ごとに100以上

まとめ

ポイント内容
SASTソースコードを実行せずに解析し、脆弱性を検出する手法
汚染解析Source→Sink間のデータフローを追跡し、サニタイズの欠如を検出
ツール選定Semgrep(OSS)、CodeQL(GitHub)、SonarQube等を比較検討
段階的導入警告のみ→Criticalブロック→全レベルブロックと段階的に導入

チェックリスト

  • SASTの解析手法(パターンマッチング、汚染解析等)を説明できる
  • 主要なSASTツールの特徴を比較できる
  • SASTルールの記述方法を理解した
  • 段階的導入戦略と誤検知対処法を理解した

次のステップへ

次は「DAST(動的解析)の基礎」を学びます。実行中のアプリケーションに対してセキュリティテストを行う手法を身につけましょう。


推定読了時間: 30分