mcpField
S
security-scanning-security-sast

security-scanning-security-sast

github.com/rmyndharisセキュリティ1.9k67 回インストール2 週間前に更新
リポジトリ

security-scanning-security-sast について

複数の言語、フレームワーク、一般的な脆弱性パターンを対象とするコードセキュリティレビュー用の SAST スキルです。スキャナーの選定やルール設定を案内し、ローカルや CI での検査、検出結果のトリアージ、修正案の作成を支援します。

主な機能

  1. 01複数のプログラミング言語に対応
  2. 02静的解析ツールの利用を案内
  3. 03一般的なコード脆弱性の検出
  4. 04フレームワーク別の安全性確認
  5. 05Semgrep カスタムルールの作成
  6. 06CI 検査と検出結果のトリアージ

活用シーン

  1. 01コードのセキュリティレビュー
  2. 02デプロイ前のインジェクションと秘密情報の確認
  3. 03組織ポリシーに沿ったルール作成
  4. 04レガシーコードの評価と修正優先度付け

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/rmyndharis/antigravity-skills --skill security-scanning-security-sast

インストール後、Claude Code で/security-scanning-security-sastを入力して読み込まれたか確認します。

詳細

SAST セキュリティプラグイン

複数の言語、フレームワーク、セキュリティパターンを対象に、コードの脆弱性を包括的に検出する静的アプリケーションセキュリティテスト(SAST)です。

機能

  • マルチ言語 SAST:Python、JavaScript/TypeScript、Java、Ruby、PHP、Go、Rust
  • ツール連携:Bandit、Semgrep、ESLint Security、SonarQube、CodeQL、PMD、SpotBugs、Brakeman、gosec、cargo-clippy
  • 脆弱性パターン:SQL インジェクション、XSS、ハードコードされたシークレット、パストラバーサル、IDOR、CSRF、安全でないデシリアライズ
  • フレームワーク分析:Django、Flask、React、Express、Spring Boot、Rails、Laravel
  • カスタムルールの作成:組織固有のセキュリティポリシーに対応する Semgrep パターンの開発

このスキルを使用する場面

コードレビューのセキュリティ分析、インジェクション脆弱性、ハードコードされたシークレット、フレームワーク固有のパターン、カスタムセキュリティポリシーの適用、デプロイ前の検証、レガシーコードの評価、コンプライアンス(OWASP、PCI-DSS、SOC2)に使用します。

専門ツール:高度な認証情報スキャンには security-secrets.md、Top 10 へのマッピングには security-owasp.md、REST/GraphQL エンドポイントには security-api.md を使用してください。

このスキルを使用しない場面

  • ランタイムテストまたはペネトレーションテストのみが必要な場合
  • ソースコードまたはビルド成果物にアクセスできない場合
  • 環境でサードパーティのスキャンツールが禁止されている場合

手順

  1. スキャン対象の言語、フレームワーク、範囲を特定します。
  2. SAST ツールを選択し、コードベースに合わせてルールを設定します。
  3. CI またはローカル環境で、再現可能な設定を使用してスキャンを実行します。
  4. 検出結果をトリアージし、深刻度に基づいて優先順位を付け、修正案を提示します。

安全性

  • 承認なしに、専有コードを外部サービスにアップロードしないでください。
  • 自動修正やリリースのブロックを有効にする前に、レビューを必須としてください。

SAST ツールの選択

Python:Bandit
# Installation & scan
pip install bandit
bandit -r . -f json -o bandit-report.json
bandit -r . -ll -ii -f json  # High/Critical only

設定:.bandit

exclude_dirs: ['/tests/', '/venv/', '/.tox/', '/build/']
tests: [B201, B301, B302, B303, B304, B305, B307, B308, B312, B323, B324, B501, B502, B506, B602, B608]
skips: [B101]
JavaScript/TypeScript:ESLint Security
npm install --save-dev eslint @eslint/plugin-security eslint-plugin-no-secrets
eslint . --ext .js,.jsx,.ts,.tsx --format json > eslint-security.json

設定:.eslintrc-security.json

{
  "plugins": ["@eslint/plugin-security", "eslint-plugin-no-secrets"],
  "extends": ["plugin:security/recommended"],
  "rules": {
    "security/detect-object-injection": "error",
    "security/detect-non-literal-fs-filename": "error",
    "security/detect-eval-with-expression": "error",
    "security/detect-pseudo-random-prng": "error",
    "no-secrets/no-secrets": "error"
  }
}
マルチ言語:Semgrep
pip install semgrep
semgrep --config=auto --json --output=semgrep-report.json
semgrep --config=p/security-audit --json
semgrep --config=p/owasp-top-ten --json
semgrep ci --config=auto  # CI mode

カスタムルール:.semgrep.yml

rules:
  - id: sql-injection-format-string
    pattern: cursor.execute("... %s ..." % $VAR)
    message: SQL injection via string formatting
    severity: ERROR
    languages: [python]
    metadata:
      cwe: "CWE-89"
      owasp: "A03:2021-Injection"

  - id: dangerous-innerHTML
    pattern: $ELEM.innerHTML = $VAR
    message: XSS via innerHTML assignment
    severity: ERROR
    languages: [javascript, typescript]
    metadata:
      cwe: "CWE-79"

  - id: hardcoded-aws-credentials
    patterns:
      - pattern: $KEY = "AKIA..."
      - metavariable-regex:
          metavariable: $KEY
          regex: "(aws_access_key_id|AWS_ACCESS_KEY_ID)"
    message: Hardcoded AWS credentials detected
    severity: ERROR
    languages: [python, javascript, java]

  - id: path-traversal-open
    patterns:
      - pattern: open($PATH, ...)
      - pattern-not: open(os.path.join(SAFE_DIR, ...), ...)
      - metavariable-pattern:
          metavariable: $PATH
          patterns:
            - pattern: $REQ.get(...)
    message: Path traversal via user input
    severity: ERROR
    languages: [python]

  - id: command-injection
    patterns:
      - pattern-either:
          - pattern: os.system($CMD)
          - pattern: subprocess.call($CMD, shell=True)
      - metavariable-pattern:
          metavariable: $CMD
          patterns:
            - pattern-either:
                - pattern: $X + $Y
                - pattern: f"...{$VAR}..."
    message: Command injection via shell=True
    severity: ERROR
    languages: [python]
その他の言語向けツール

Java:mvn spotbugs:check Ruby:brakeman -o report.json -f json Go:gosec -fmt=json -out=gosec.json ./... Rust:cargo clippy -- -W clippy::unwrap_used

脆弱性パターン

SQL インジェクション

脆弱:SQL クエリ内で、ユーザー入力を文字列フォーマットまたは連結する

安全:

# Parameterized queries
cursor.execute("SELECT * FROM users WHERE id = %s", (user_id,))
User.objects.filter(id=user_id)  # ORM
クロスサイトスクリプティング(XSS)

脆弱:サニタイズされていないユーザー入力で HTML を直接操作する(innerHTML、outerHTML、document.write)

安全:

// Use textContent for plain text
element.textContent = userInput;

// React auto-escapes
<div>{userInput}</div>

// Sanitize when HTML required
import DOMPurify from 'dompurify';
element.innerHTML = DOMPurify.sanitize(userInput);
ハードコードされたシークレット

脆弱:ソースコードに API キー、パスワード、トークンをハードコードする

安全:

import os
API_KEY = os.environ.get('API_KEY')
PASSWORD = os.getenv('DB_PASSWORD')
パストラバーサル

脆弱:サニタイズされていないユーザー入力を使ってファイルを開く

安全:

import os
ALLOWED_DIR = '/var/www/uploads'
file_name = request.args.get('file')
file_path = os.path.join(ALLOWED_DIR, file_name)
file_path = os.path.realpath(file_path)
if not file_path.startswith(os.path.realpath(ALLOWED_DIR)):
    raise ValueError("Invalid file path")
with open(file_path, 'r') as f:
    content = f.read()
安全でないデシリアライズ

脆弱:信頼できないデータに対して pickle.loads()、yaml.load() を使用する

安全:

import json
data = json.loads(user_input)  # SECURE
import yaml
config = yaml.safe_load(user_input)  # SECURE
コマンドインジェクション

脆弱:os.system()、または shell=True を指定した subprocess でユーザー入力を使用する

安全:

subprocess.run(['ping', '-c', '4', user_input])  # Array args
import shlex
safe_input = shlex.quote(user_input)  # Input validation
安全でない乱数

脆弱:セキュリティ上重要な処理に random モジュールを使用する

安全:

import secrets
token = secrets.token_hex(16)
session_id = secrets.token_urlsafe(32)

フレームワークのセキュリティ

Django

脆弱:@csrf_exempt、DEBUG=True、弱い SECRET_KEY、セキュリティミドルウェアの欠如

安全:

# settings.py
DEBUG = False
SECRET_KEY = os.environ.get('DJANGO_SECRET_KEY')

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

SECURE_SSL_REDIRECT = True
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
X_FRAME_OPTIONS = 'DENY'
Flask

脆弱:debug=True、弱い secret_key、CORS のワイルドカード指定

安全:

import os
from flask_talisman import Talisman

app.secret_key = os.environ.get('FLASK_SECRET_KEY')
Talisman(app, force_https=True)
CORS(app, origins=['https://example.com'])
Express.js

脆弱:helmet の欠如、CORS のワイルドカード指定、レート制限なし

安全:

const helmet = require('helmet');
const rateLimit = require('express-rate-limit');

app.use(helmet());
app.use(cors({ origin: 'https://example.com' }));
app.use(rateLimit({ windowMs: 15 * 60 * 1000, max: 100 }));

マルチ言語スキャナーの実装

import json
import subprocess
from pathlib import Path
from typing import Dict, List, Any
from dataclasses import dataclass
from datetime import datetime

@dataclass
class SASTFinding:
    tool: str
    severity: str
    category: str
    title: str
    description: str
    file_path: str
    line_number: int
    cwe: str
    owasp: str
    confidence: str

class MultiLanguageSASTScanner:
    def __init__(self, project_path: str):
        self.project_path = Path(project_path)
        self.findings: List[SASTFinding] = []

    def detect_languages(self) -> List[str]:
        """Auto-detect languages"""
        languages = []
        indicators = {
            'python': ['*.py', 'requirements.txt'],
            'javascript': ['*.js', 'package.json'],
            'typescript': ['*.ts', 'tsconfig.json'],
            'java': ['*.java', 'pom.xml'],
            'ruby': ['*.rb', 'Gemfile'],
            'go': ['*.go', 'go.mod'],
            'rust': ['*.rs', 'Cargo.toml'],
        }
        for lang, patterns in indicators.items():
            for pattern in patterns:
                if list(self.project_path.glob(f'**/{pattern}')):
                    languages.append(lang)
                    break
        return languages

    def run_comprehensive_sast(self) -> Dict[str, Any]:
        """Execute all applicable SAST tools"""
        languages = self.detect_languages()

        scan_results = {
            'timestamp': datetime.now().isoformat(),
            'languages': languages,
            'tools_executed': [],
            'findings': []
        }

        self.run_semgrep_scan()
        scan_results['tools_executed'].append('semgrep')

        if 'python' in languages:
            self.run_bandit_scan()
            scan_results['tools_executed'].append('bandit')
        if 'javascript' in languages or 'typescript' in languages:
            self.run_eslint_security_scan()
            scan_results['tools_executed'].append('eslint-security')

        scan_results['findings'] = [vars(f) for f in self.findings]
        scan_results['summary'] = self.generate_summary()
        return scan_results

    def run_semgrep_scan(self):
        """Run Semgrep"""
        for ruleset in ['auto', 'p/security-audit', 'p/owasp-top-ten']:
            try:
                result = subprocess.run([
                    'semgrep', '--config', ruleset, '--json', '--quiet',
                    str(self.project_path)
                ], capture_output=True, text=True, timeout=300)

                if result.stdout:
                    data = json.loads(result.stdout)
                    for f in data.get('results', []):
                        self.findings.append(SASTFinding(
                            tool='semgrep',
                            severity=f.get('extra', {}).get('severity', 'MEDIUM').upper(),
                            category='sast',
                            title=f.get('check_id', ''),
                            description=f.get('extra', {}).get('message', ''),
                            file_path=f.get('path', ''),
                            line_number=f.get('start', {}).get('line', 0),
                            cwe=f.get('extra', {}).get('metadata', {}).get('cwe', ''),
                            owasp=f.get('extra', {}).get('metadata', {}).get('owasp', ''),
                            confidence=f.get('extra', {}).get('metadata', {}).get('confidence', 'MEDIUM')
                        ))
            except Exception as e:
                print(f"Semgrep {ruleset} failed: {e}")

    def generate_summary(self) -> Dict[str, Any]:
        """Generate statistics"""
        severity_counts = {'CRITICAL': 0, 'HIGH': 0, 'MEDIUM': 0, 'LOW': 0}
        for f in self.findings:
            severity_counts[f.severity] = severity_counts.get(f.severity, 0) + 1

        return {
            'total_findings': len(self.findings),
            'severity_breakdown': severity_counts,
            'risk_score': self.calculate_risk_score(severity_counts)
        }

    def calculate_risk_score(self, severity_counts: Dict[str, int]) -> int:
        """Risk score 0-100"""
        weights = {'CRITICAL': 10, 'HIGH': 7, 'MEDIUM': 4, 'LOW': 1}
        total = sum(weights[s] * c for s, c in severity_counts.items())
        return min(100, int((total / 50) * 100))

CI/CD 連携

GitHub Actions
name: SAST Scan
on:
  pull_request:
    branches: [main]

jobs:
  sast:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-python@v4
        with:
          python-version: '3.11'

      - name: Install tools
        run: |
          pip install bandit semgrep
          npm install -g eslint @eslint/plugin-security

      - name: Run scans
        run: |
          bandit -r . -f json -o bandit.json || true
          semgrep --config=auto --json --output=semgrep.json || true

      - name: Upload reports
        uses: actions/upload-artifact@v3
        with:
          name: sast-reports
          path: |
            bandit.json
            semgrep.json
GitLab CI
sast:
  stage: test
  image: python:3.11
  script:
    - pip install bandit semgrep
    - bandit -r . -f json -o bandit.json || true
    - semgrep --config=auto --json --output=semgrep.json || true
  artifacts:
    reports:
      sast: bandit.json

ベストプラクティス

  1. 早期かつ頻繁に実行する - コミット前フックと CI/CD
  2. 複数のツールを組み合わせる - ツールごとに検出できる脆弱性が異なります
  3. 誤検知を調整する - 除外項目としきい値を設定します
  4. 検出結果に優先順位を付ける - まず CRITICAL/HIGH に対応します
  5. フレームワークを考慮したスキャン - 専用のルールセットを使用します
  6. カスタムルール - 組織固有のパターン
  7. 開発者のトレーニング - セキュアなコーディングプラクティス
  8. 段階的な修正 - 少しずつ修正します
  9. ベースライン管理 - 既知の問題を追跡します
  10. 定期的な更新 - ツールを最新の状態に保ちます

関連ツール

  • security-secrets.md - 高度な認証情報の検出
  • security-owasp.md - OWASP Top 10 の評価
  • security-api.md - API セキュリティテスト
  • security-scan.md - 包括的なセキュリティスキャン

コメント