LESSON 40分

ストーリー

佐藤CTO
パイプラインの最初のセキュリティゲートはコード自体のスキャン

佐藤CTOがSonarQubeのダッシュボードを開きました。

佐藤CTO
SAST — 静的解析でコードの脆弱性を検出する。SCA — 依存ライブラリの脆弱性をチェックする。そしてシークレットスキャン — コードに埋め込まれた秘密情報を検出する
あなた
ビルドする前に問題を見つけるんですね
佐藤CTO
そうだ。コードを書いた直後が最も修正コストが低い。IDEプラグイン、Git hooks、CI/CD — 複数の段階でスキャンを仕掛ける

SAST(Static Application Security Testing)

SASTの仕組み

SASTはソースコードやバイトコードを実行せずに解析し、セキュリティ上の脆弱性を検出します。

特徴説明
解析対象ソースコード、バイトコード
実行タイミングビルド前(コードレビュー時)
検出できるものSQLi, XSS, パストラバーサル, バッファオーバーフロー等
検出できないものランタイムの設定ミス、ビジネスロジックの欠陥
長所早期発見、全コードパスの網羅的チェック
短所False Positive(誤検知)が多い

主要SASTツール

ツール対応言語特徴ライセンス
Semgrep多言語カスタムルール記述が容易OSS + Commercial
SonarQube多言語品質+セキュリティの統合Community/Enterprise
CodeQL多言語GitHub統合、クエリ言語OSS (GitHub)
ESLint SecurityJavaScript/TypeScript既存のESLintに追加OSS
BanditPythonPython特化OSS

Semgrepのカスタムルール

# .semgrep/custom-rules.yml
rules:
  # SQLインジェクション検出
  - id: sql-injection-template-literal
    pattern: |
      $DB.query(`...${$INPUT}...`)
    message: "テンプレートリテラルでのSQL構築は SQLインジェクションのリスクがあります。パラメータ化クエリを使用してください。"
    languages: [typescript, javascript]
    severity: ERROR
    metadata:
      category: security
      cwe: "CWE-89: SQL Injection"
      owasp: "A03:2021 - Injection"
    fix: |
      $DB.query('... $1 ...', [$INPUT])

  # ハードコードされた認証情報
  - id: hardcoded-credentials
    patterns:
      - pattern: |
          const $VAR = "$SECRET"
      - metavariable-regex:
          metavariable: $VAR
          regex: (password|secret|apiKey|api_key|token|credential)
      - metavariable-regex:
          metavariable: $SECRET
          regex: .{8,}
    message: "ハードコードされた認証情報が検出されました。環境変数またはシークレットマネージャーを使用してください。"
    languages: [typescript, javascript]
    severity: ERROR

  # eval() の使用禁止
  - id: no-eval
    pattern: eval($X)
    message: "eval() の使用はコードインジェクションのリスクがあります。"
    languages: [typescript, javascript]
    severity: ERROR
    metadata:
      cwe: "CWE-95: Eval Injection"

  # innerHTML の使用検出
  - id: no-innerhtml
    pattern: $EL.innerHTML = $X
    message: "innerHTML の直接代入はXSSのリスクがあります。textContent または DOMPurify を使用してください。"
    languages: [typescript, javascript]
    severity: WARNING
    metadata:
      cwe: "CWE-79: Cross-site Scripting"

SonarQubeの設定

// sonar-project.properties
// sonar.projectKey=my-project
// sonar.sources=src
// sonar.tests=tests
// sonar.typescript.lcov.reportPaths=coverage/lcov.info
// sonar.qualitygate.wait=true

// Quality Gateの条件例(TypeScript)
interface SonarQualityGate {
  conditions: {
    metric: string;
    operator: 'GT' | 'LT';
    threshold: number;
  }[];
}

const securityQualityGate: SonarQualityGate = {
  conditions: [
    { metric: 'new_security_rating', operator: 'GT', threshold: 1 },       // A(脆弱性なし)
    { metric: 'new_security_hotspots_reviewed', operator: 'LT', threshold: 100 }, // 全ホットスポットレビュー済み
    { metric: 'new_vulnerabilities', operator: 'GT', threshold: 0 },       // 新規脆弱性ゼロ
    { metric: 'new_coverage', operator: 'LT', threshold: 80 },            // カバレッジ80%以上
  ],
};

SCA(Software Composition Analysis)

SCAの仕組み

SCAは、プロジェクトが使用するオープンソースライブラリとその依存関係の脆弱性を検出します。

特徴説明
解析対象package.json, lock files, コンテナイメージ
脆弱性DBNVD, GitHub Advisory, Snyk DB
検出対象既知の脆弱性(CVE)、ライセンス違反
推移的依存関係直接依存だけでなく、間接依存も検出

Snyk によるSCA

// .snyk ポリシーファイル
// 特定の脆弱性を一時的に無視する設定
const snykPolicy = {
  version: 'v1.25.0',
  ignore: {
    // 緩和策適用済みの脆弱性を90日間無視
    'SNYK-JS-LODASH-1018905': {
      reason: 'WAFでサニタイズ済み。次のメジャーアップデートで対応予定。',
      expires: '2024-06-30T00:00:00.000Z',
    },
  },
  patch: {},
};
# GitHub Actions での Snyk SCA実行
- name: Snyk Security Check
  uses: snyk/actions/node@master
  env:
    SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
  with:
    args: >-
      --severity-threshold=high
      --fail-on=all
      --json-file-output=snyk-results.json

# npm audit の活用
- name: npm audit
  run: |
    npm audit --audit-level=high --json > audit-results.json || true
    # Critical/High の脆弱性がある場合はビルドを失敗させる
    CRITICAL=$(cat audit-results.json | jq '.metadata.vulnerabilities.critical')
    HIGH=$(cat audit-results.json | jq '.metadata.vulnerabilities.high')
    if [ "$CRITICAL" -gt 0 ] || [ "$HIGH" -gt 0 ]; then
      echo "Critical: $CRITICAL, High: $HIGH vulnerabilities found"
      exit 1
    fi

SBOM(Software Bill of Materials)

SBOMは、ソフトウェアに含まれる全コンポーネントの一覧です。

# SBOM生成(Syft)
# syft app:latest -o spdx-json > sbom.spdx.json

# SBOM例(SPDX形式の一部)
spdxVersion: "SPDX-2.3"
name: "my-application"
packages:
  - name: "express"
    versionInfo: "4.18.2"
    supplier: "Organization: Express Contributors"
    downloadLocation: "https://registry.npmjs.org/express/-/express-4.18.2.tgz"
    licenseConcluded: "MIT"
    externalRefs:
      - referenceCategory: SECURITY
        referenceType: cpe23Type
        referenceLocator: "cpe:2.3:a:expressjs:express:4.18.2:*:*:*:*:node.js:*:*"

シークレットスキャン

検出対象のシークレットパターン

パターンリスク
AWS アクセスキーAKIA...AWSリソースへの不正アクセス
GitHub トークンghp_..., github_pat_...リポジトリの不正操作
JWT署名鍵-----BEGIN RSA PRIVATE KEY-----トークン偽造
データベース接続文字列postgresql://user:pass@host/dbデータ漏洩
Slack Webhookhttps://hooks.slack.com/...チャネルへの不正投稿

GitLeaks の設定

# .gitleaks.toml
title = "Custom Gitleaks Config"

[extend]
useDefault = true

# カスタムルール追加
[[rules]]
id = "custom-internal-api-key"
description = "Internal API Key"
regex = '''internal-api-key-[a-zA-Z0-9]{32}'''
tags = ["key", "internal"]

[[rules]]
id = "custom-database-url"
description = "Database URL with credentials"
regex = '''(postgres|mysql|mongodb)://[^:]+:[^@]+@[^/]+/\w+'''
tags = ["database", "credential"]

# 許可リスト(テストファイル等)
[allowlist]
paths = [
  '''tests/fixtures/.*''',
  '''docs/examples/.*''',
]
regexTarget = "line"
regexes = [
  '''EXAMPLE_.*''',
  '''test-api-key-.*''',
]

Pre-commit Hook の設定

# .pre-commit-config.yaml
repos:
  - repo: https://github.com/gitleaks/gitleaks
    rev: v8.18.0
    hooks:
      - id: gitleaks

  - repo: https://github.com/semgrep/semgrep
    rev: v1.50.0
    hooks:
      - id: semgrep
        args: ['--config', 'p/security-audit', '--error']

  - repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v4.5.0
    hooks:
      - id: detect-private-key
      - id: detect-aws-credentials

運用のベストプラクティス

False Positive(誤検知)の管理

戦略説明
ベースラインの設定既存の指摘事項をベースラインとし、新規のみ報告
抑制ルール明確な誤検知はルールで抑制
トリアージプロセスセキュリティチャンピオンが定期的にレビュー
フィードバック誤検知をツールベンダーに報告して改善
// 脆弱性トリアージの自動化
interface VulnerabilityTriagePolicy {
  autoFix: {
    enabled: boolean;
    types: string[];       // dependabot auto-merge対象
    maxSeverity: string;   // auto-fixの上限
  };
  escalation: {
    critical: { notifyChannel: string; sla: string };
    high: { notifyChannel: string; sla: string };
    medium: { assignTeam: string; sla: string };
    low: { trackInBacklog: boolean };
  };
}

const triagePolicy: VulnerabilityTriagePolicy = {
  autoFix: {
    enabled: true,
    types: ['patch-update', 'minor-update'],
    maxSeverity: 'medium',
  },
  escalation: {
    critical: { notifyChannel: '#security-incidents', sla: '4h' },
    high: { notifyChannel: '#security-alerts', sla: '24h' },
    medium: { assignTeam: 'security-champions', sla: '7d' },
    low: { trackInBacklog: true },
  },
};

まとめ

ポイント内容
SASTソースコードの静的解析で脆弱性を検出(Semgrep, SonarQube, CodeQL)
SCA依存ライブラリの既知の脆弱性を検出(Snyk, npm audit)
シークレットスキャンコードに埋め込まれた秘密情報を検出(GitLeaks)
SBOMソフトウェアの構成要素を一覧化し、サプライチェーンリスクを管理
Pre-commitコミット前にローカルでスキャンし、問題の混入を防止

チェックリスト

  • SAST / SCA / シークレットスキャンの違いを説明できる
  • Semgrepのカスタムルールを記述できる
  • Snykを使った依存関係の脆弱性チェックを設定できる
  • GitLeaksでシークレットスキャンを構成できる
  • Pre-commit hookでローカルスキャンを設定できる

次のステップへ

次は「DAST・コンテナセキュリティ」を学びます。実行中のアプリケーションに対する動的テストと、コンテナイメージのセキュリティスキャンを身につけましょう。


推定読了時間: 40分