mcpField
P
py-security

py-security

github.com/l-mbセキュリティ5650 回インストール34 週間前に更新
リポジトリ

py-security について

py-security は、Python コードのセキュリティリスクを検出して修正する Claude スキルです。bandit と Ruff によるスキャンを案内し、SQL インジェクション、ハードコードされた秘密情報、弱い暗号化、安全でないシェルコマンドなどを扱います。

主な機能

  1. 01bandit と Ruff のセキュリティルールでスキャン
  2. 02SQL インジェクションリスクの特定
  3. 03ハードコードされた秘密情報の検出
  4. 04暗号化とシェルコマンドのリスク確認
  5. 05安全なコーディングパターンの適用

活用シーン

  1. 01Python リポジトリの脆弱性監査
  2. 02ハードコードされた認証情報の環境変数への移行
  3. 03リリース前の SQL クエリとシェルコマンドの確認

インストール

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

$npx skills add https://github.com/l-mb/python-refactoring-skills --skill py-security

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

詳細

Python のセキュリティ分析と修正

Engineering Charter のセキュリティ原則に従って、Python コードのセキュリティ脆弱性を検出して修正します。

目標

  1. 自動スキャナーを使用してセキュリティ脆弱性を検出する
  2. SQL インジェクションのリスクを特定する
  3. ハードコードされたシークレットと認証情報を見つける
  4. 脆弱な暗号化手法を検出する
  5. セキュアなコーディングパターンに従って脆弱性を修正する
  6. シークレットが git にコミットされるのを防ぐ

必要なツール

[dependency-groups] の dev に追加:"bandit"、"ruff"

  • bandit:AST ベースのセキュリティスキャナー
  • ruff --select S:組み込みの Bandit ルール(より高速な代替手段)

権限:最初に py-quality-setup を実行し、必要なすべてのツール権限を .claude/settings.local.json に設定します。

検出フェーズ

セキュリティスキャナーを実行する
# Using bandit (comprehensive reports)
bandit -r . -f json -o bandit_report.json
bandit -r . -ll  # Show only medium/high severity

# Using ruff (faster, integrates with existing tooling)
ruff check . --select S
ruff check . --select S --output-format=json > security_report.json
よくある脆弱性のカテゴリ

重大度:高(直ちに修正):

  • S608:文字列フォーマットによる SQL インジェクション
  • S105、S106、S107:ハードコードされたパスワード、シークレット、キー
  • S501、S506:脆弱な SSL/TLS 設定
  • S324:安全でないハッシュ関数(MD5、SHA1)
  • S602、S603、S604、S605、S606、S607:シェルインジェクションのリスク

重大度:中:

  • S311:安全でない乱数生成
  • S301、S302、S303:安全でないデシリアライズ(pickle)
  • S701、S702:Jinja2 の autoescape に関する問題

重大度:低(状況を考慮):

  • S101:assert の使用(本番環境では無効化される)
  • S104:すべてのインターフェースへのバインド(0.0.0.0)

修正パターン

SQL インジェクションの防止
# BEFORE - Vulnerable to SQL injection
def get_user(user_id: str) -> dict:
    cursor.execute(f"SELECT * FROM users WHERE id = {user_id}")
    return cursor.fetchone()

# AFTER - Use parametrized queries
def get_user(user_id: str) -> dict:
    cursor.execute("SELECT * FROM users WHERE id = %s", (user_id,))
    return cursor.fetchone()

# For dynamic table/column names (cannot be parametrized)
from psycopg2 import sql

def get_data(table_name: str, column: str) -> list:
    # Validate inputs first!
    allowed_tables = {"users", "orders", "products"}
    if table_name not in allowed_tables:
        raise ValueError(f"Invalid table: {table_name}")

    query = sql.SQL("SELECT {column} FROM {table}").format(
        column=sql.Identifier(column),
        table=sql.Identifier(table_name)
    )
    cursor.execute(query)
    return cursor.fetchall()
ハードコードされたシークレットの削除
# BEFORE - Hardcoded secrets (NEVER commit these)
API_KEY = "sk-1234567890abcdef"
DATABASE_URL = "postgres://user:password@localhost/db"
SECRET_TOKEN = "my-secret-token-123"

# AFTER - Use environment variables
import os

API_KEY = os.environ["API_KEY"]  # Raises if not set
DATABASE_URL = os.getenv("DATABASE_URL", "postgres://localhost/db")  # With default
SECRET_TOKEN = os.environ.get("SECRET_TOKEN")  # Returns None if not set

# For development, use python-dotenv
from dotenv import load_dotenv
load_dotenv()  # Loads from .env file (add .env to .gitignore!)
API_KEY = os.environ["API_KEY"]
セキュアな乱数生成
# BEFORE - Insecure for security-sensitive operations
import random

session_token = random.randint(100000, 999999)
api_key = ''.join(random.choices('abcdef0123456789', k=32))

# AFTER - Use secrets module for cryptographic randomness
import secrets

session_token = secrets.randbelow(900000) + 100000
api_key = secrets.token_hex(16)  # 32 hex characters
secure_password = secrets.token_urlsafe(32)  # URL-safe token
セキュアな暗号化
# BEFORE - Weak hash functions
import hashlib

password_hash = hashlib.md5(password.encode()).hexdigest()  # Weak!
checksum = hashlib.sha1(data).hexdigest()  # Weak for security!

# AFTER - Use strong hash functions
import hashlib

# For passwords - use bcrypt or argon2
from argon2 import PasswordHasher
ph = PasswordHasher()
password_hash = ph.hash(password)
ph.verify(password_hash, password)  # Verify

# For data integrity - use SHA256 or better
checksum = hashlib.sha256(data).hexdigest()
secure_hash = hashlib.blake2b(data).hexdigest()
シェルコマンドインジェクションの防止
# BEFORE - Shell injection vulnerability
import os
import subprocess

filename = user_input
os.system(f"cat {filename}")  # Dangerous!
subprocess.call(f"ls {directory}", shell=True)  # Dangerous!

# AFTER - Use subprocess with list arguments (no shell)
import subprocess
from pathlib import Path

# Validate input first
filename = user_input
if not Path(filename).exists():
    raise ValueError("File not found")

# Use list form, no shell=True
subprocess.run(["cat", filename], check=True)
subprocess.run(["ls", directory], check=True)

# Even better - use Python libraries instead of shell commands
with open(filename) as f:
    content = f.read()

Git フックとの統合

git フックにシークレット検出を追加します(py-git-hooks を補完します):

# In .git/hooks/pre-commit, add before other checks:

# Detect potential secrets
if git diff --cached | grep -qiE '(password|secret|api[_-]?key|token|credentials)'; then
    echo "⚠️  Warning: Potential secrets detected in staged changes"
    echo "Review carefully before committing"
    read -p "Continue? (y/n) " -n 1 -r
    echo
    if [[ ! $REPLY =~ ^[Yy]$ ]]; then
        exit 1
    fi
fi

検証チェックリスト

  • ruff check . --select S でセキュリティ上の問題が報告されない
  • bandit -r . -ll で重大度が中または高の問題が報告されない
  • コードベースにハードコードされたシークレットがない(password、secret、api_key、token を grep で検索)
  • シークレットが環境変数または .env ファイルから読み込まれている
  • .env ファイルが .gitignore に含まれている
  • すべての SQL クエリでパラメーター化クエリを使用している
  • セキュリティ修正後にすべてのテストが成功する

例

例:セキュリティ監査ワークフロー

1. Scan: ruff check . --select S; bandit -r . -ll
2. Found: SQL injection (S608), hardcoded secret (S105)
3. Fix SQL: Use parametrized query with %s placeholders
4. Fix secret: Move to .env, use os.environ["API_KEY"]
5. Verify: Scans clean, tests pass

関連スキル

  • 前提条件:py-quality-setup(セキュリティチェック用に ruff を設定)
  • 適用:py-git-hooks(pre-commit にセキュリティスキャンを追加)
  • 関連項目:py-code-health(セキュリティ修正後のクリーンアップ)

コメント