mcpField
P
python

python

github.com/martinholovsky開発48228 回インストール47 週間前に更新
リポジトリ

python について

Python バックエンド開発向けのスキルガイドで、型安全性、非同期処理、テスト、セキュリティを扱います。保守しやすいサービスの構築やレビューに向け、入力検証からデプロイ前確認までの実践パターンを示します。

主な機能

  1. 01型注釈と実行時検証
  2. 02asyncio とパフォーマンスパターン
  3. 03TDD、pytest、型チェック
  4. 04安全な DB・ファイル・サブプロセス操作
  5. 05脆弱性対策とデプロイチェックリスト

活用シーン

  1. 01安全な API 入力検証の設計
  2. 02非同期データベースアクセスの実装
  3. 03インジェクションやパストラバーサルの確認
  4. 04デプロイ前のテストと依存関係監査

インストール

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

$npx skills add https://github.com/martinholovsky/claude-skills-generator --skill python

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

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

references/
advanced-patterns.md
security-examples.md
threat-model.md

詳細

Python バックエンド開発スキル

ファイル構成

このスキルでは、リスクの高い要件に対応するため、ファイルを分割しています。

  • SKILL.md:基本原則、パターン、セキュリティの必須事項(このファイル)
  • references/security-examples.md:CVE の詳細と OWASP の実装例一式
  • references/advanced-patterns.md:高度な Python パターンと最適化
  • references/threat-model.md:攻撃シナリオと STRIDE 分析

検証ゲート

ゲート状態備考
0.1 ドメインの専門知識合格型安全性、非同期処理、セキュリティ、テスト
0.2 脆弱性の調査合格5 件以上の CVE を記録(2025-11-20)
0.5 ハルシネーションの確認合格Python 3.11 以降で例をテスト済み
0.11 ファイル構成分割リスクが高い要件、約 450 行+参照資料

1. 概要

リスクレベル:高

理由:Python バックエンドサービスは、認証、データベースアクセス、ファイル操作、外部 API との通信を処理します。入力検証、デシリアライズ、コマンド実行、暗号化の脆弱性は、データ漏えいやシステム侵害につながる可能性があります。

あなたは、安全で保守しやすく、高性能なサービスを専門とする、Python バックエンド開発のエキスパートです。

主な専門分野
  • 型注釈と実行時検証
  • asyncio による非同期プログラミング
  • セキュリティ:入力検証、暗号化、シークレット管理
  • テスト:pytest、プロパティベーステスト、セキュリティテスト
  • SQLAlchemy/asyncpg によるデータベースアクセス
  • FastAPI/Starlette による API 開発

2. 主な責務

基本原則
  1. まず TDD:実装の前にテストを書き、テストケースを通じて API を設計します
  2. パフォーマンスを意識:デフォルトで、非同期処理、ジェネレーター、効率的なデータ構造を使用します
  3. 型安全性:あらゆる箇所で型ヒントを使用し、実行時の境界で検証します
  4. 多層防御:複数の検証層を設け、安全に失敗するようにします
  5. 安全なデフォルト設定:安全なライブラリを使用し、安全でない操作を拒否します
  6. 暗黙的な処理より明示的な処理:明確なエラー処理と、明示的な依存関係を使用します
  7. テスト容易性:テストしやすい設計にし、セキュリティテストを作成します
判断基準
状況アプローチ
ユーザー入力Pydantic で検証し、出力をサニタイズします
データベースクエリORM またはパラメーター化クエリを使用し、文字列のフォーマットは決して使いません
ファイル操作パスを検証し、pathlib を使用して、パスが指定範囲内にあることを確認します
サブプロセス引数リストを使用し、ユーザー入力に対して shell=True を決して使用しません
シークレット環境変数またはシークレットマネージャーから読み込みます
暗号化cryptography ライブラリを使用し、独自実装は決して行いません

2.1 実装ワークフロー(TDD)

ステップ 1:まず失敗するテストを書く
import pytest
from my_service import UserService, UserNotFoundError

class TestUserService:
    @pytest.mark.asyncio
    async def test_get_user_returns_user_when_exists(self, db_session):
        service = UserService(db_session)
        user_id = await service.create_user("alice", "[email protected]")
        user = await service.get_user(user_id)
        assert user.username == "alice"

    @pytest.mark.asyncio
    async def test_get_user_raises_when_not_found(self, db_session):
        service = UserService(db_session)
        with pytest.raises(UserNotFoundError):
            await service.get_user(99999)

    @pytest.mark.asyncio
    async def test_create_user_validates_email(self, db_session):
        service = UserService(db_session)
        with pytest.raises(ValueError, match="Invalid email"):
            await service.create_user("bob", "not-an-email")
ステップ 2:テストに合格するための最小限の実装を行う
class UserNotFoundError(Exception): pass

class UserService:
    def __init__(self, db: AsyncSession):
        self.db = db

    async def get_user(self, user_id: int) -> User:
        user = await self.db.get(User, user_id)
        if not user:
            raise UserNotFoundError(f"User {user_id} not found")
        return user

    async def create_user(self, username: str, email: str) -> int:
        if "@" not in email:
            raise ValueError("Invalid email format")
        # ... minimal implementation to pass tests
ステップ 3:必要に応じてリファクタリングする
  • 共通パターンを抽出し、型ヒントを追加して、エラーから内部情報が漏れないようにします
ステップ 4:完全な検証を実行する
pytest --cov=src           # All tests pass
mypy src/ --strict         # Type check passes
bandit -r src/ -ll         # Security scan passes
pip-audit && safety check  # Dependencies clean

2.2 パフォーマンスパターン

パターン 1:asyncio.gather による非同期 I/O
# BAD: Sequential requests (slow)
for url in urls:
    response = await client.get(url)  # Waits for each one

# GOOD: Concurrent requests with gather
tasks = [client.get(url) for url in urls]
responses = await asyncio.gather(*tasks)  # All at once
パターン 2:大量データ処理にジェネレーターを使用する
# BAD: Load all into memory
return [process(line) for line in f.readlines()]  # OOM risk

# GOOD: Generator yields one at a time
def process_large_file(filepath: str) -> Iterator[dict]:
    with open(filepath) as f:
        for line in f:
            yield process(line)  # Memory efficient
パターン 3:効率的なデータ構造
# BAD: List for membership testing - O(n)
required in user_perms_list  # Slow for large lists

# GOOD: Set for membership testing - O(1)
required in user_perms_set  # Fast lookup

# BAD: Repeated string concatenation
result = ""; for f in fields: result += f + ", "  # Creates new string each time

# GOOD: Join for string building
", ".join(fields)  # Single allocation
パターン 4:コネクションプーリング
# BAD: New connection per request
engine = create_async_engine(DATABASE_URL)  # Connection overhead each time

# GOOD: Reuse pooled connections
engine = create_async_engine(DATABASE_URL, pool_size=20, max_overflow=10)
async_session = sessionmaker(engine, class_=AsyncSession)

async def get_user(user_id: int):
    async with async_session() as session:  # Reuses pooled connection
        return await session.get(User, user_id)
パターン 5:データベース操作のバッチ処理
# BAD: Individual inserts (N round trips)
for user in users:
    db.add(User(**user)); await db.commit()  # N commits = slow

# GOOD: Batch insert (1 round trip)
stmt = insert(User).values(users)
await db.execute(stmt); await db.commit()  # Single commit

# GOOD: Chunked for very large datasets
for i in range(0, len(users), 1000):
    await db.execute(insert(User).values(users[i:i+1000]))
await db.commit()

3. 技術基盤

推奨バージョン
カテゴリーバージョン備考
LTS/推奨Python 3.11 以降パフォーマンスの改善、より分かりやすいエラー
最小要件Python 3.9セキュリティサポートは 2025 年 10 月まで
非推奨Python 3.8 以前EOL、セキュリティパッチなし
セキュリティ依存関係
# pyproject.toml
[project]
dependencies = [
    "pydantic>=2.0", "email-validator>=2.0",      # Validation
    "cryptography>=41.0", "argon2-cffi>=21.0",    # Cryptography
    "PyJWT>=2.8", "sqlalchemy>=2.0", "asyncpg>=0.28",
    "httpx>=0.25", "bandit>=1.7",
]

[project.optional-dependencies]
dev = ["pytest>=7.0", "pytest-asyncio>=0.21", "hypothesis>=6.0", "safety>=2.0", "pip-audit>=2.0"]

4. 実装パターン

パターン 1:型安全な入力検証
from pydantic import BaseModel, Field, field_validator, EmailStr
from typing import Annotated
import re

class UserCreate(BaseModel):
    """Validated user creation request."""
    username: Annotated[str, Field(min_length=3, max_length=50)]
    email: EmailStr
    password: Annotated[str, Field(min_length=12)]

    @field_validator('username')
    @classmethod
    def validate_username(cls, v: str) -> str:
        if not re.match(r'^[a-zA-Z0-9_-]+$', v):
            raise ValueError('Username must be alphanumeric')
        return v

    @field_validator('password')
    @classmethod
    def validate_password_strength(cls, v: str) -> str:
        if not all([re.search(r'[A-Z]', v), re.search(r'[a-z]', v), re.search(r'\d', v)]):
            raise ValueError('Password needs uppercase, lowercase, and digit')
        return v
パターン 2:安全なパスワードハッシュ化
from argon2 import PasswordHasher
from argon2.exceptions import VerifyMismatchError

ph = PasswordHasher(time_cost=3, memory_cost=65536, parallelism=4)

def hash_password(password: str) -> str:
    return ph.hash(password)

def verify_password(password: str, hash: str) -> bool:
    try:
        ph.verify(hash, password)
        return True
    except VerifyMismatchError:
        return False
パターン 3:安全なデータベースクエリ
from sqlalchemy import select, text
from sqlalchemy.ext.asyncio import AsyncSession

# NEVER: f"SELECT * FROM users WHERE username = '{username}'"

async def get_user_safe(db: AsyncSession, username: str) -> User | None:
    stmt = select(User).where(User.username == username)
    result = await db.execute(stmt)
    return result.scalar_one_or_none()

async def search_users(db: AsyncSession, pattern: str) -> list:
    stmt = text("SELECT * FROM users WHERE username LIKE :pattern")
    result = await db.execute(stmt, {"pattern": f"%{pattern}%"})
    return result.fetchall()
パターン 4:安全なファイル操作
from pathlib import Path

def safe_read_file(base_dir: Path, user_filename: str) -> str:
    if '..' in user_filename or user_filename.startswith('/'):
        raise ValueError("Invalid filename")

    file_path = (base_dir / user_filename).resolve()
    if not file_path.is_relative_to(base_dir.resolve()):
        raise ValueError("Path traversal detected")

    return file_path.read_text()
パターン 5:安全なサブプロセス実行
import subprocess

ALLOWED_PROGRAMS = {'git', 'python', 'pip'}

def run_command_safe(program: str, args: list[str]) -> str:
    if program not in ALLOWED_PROGRAMS:
        raise ValueError(f"Program not allowed: {program}")

    result = subprocess.run(
        [program, *args],
        capture_output=True, text=True, timeout=30, check=True,
    )
    return result.stdout

5. セキュリティ標準

5.1 ドメインの脆弱性の状況
CVE ID重大度説明緩和策
CVE-2024-12718CRITICALtarfile フィルターのバイパスPython 3.12.3+、filter='data'
CVE-2024-12254HIGHasyncio のメモリ枯渇アップグレード、メモリを監視
CVE-2024-5535MEDIUMSSLContext のバッファー範囲外読み取りOpenSSL をアップグレード
CVE-2023-50782HIGHRSA の情報漏えいcryptography をアップグレード
CVE-2023-27043MEDIUMメール解析の脆弱性厳格なメール検証

CVE の詳細と緩和策のコードについては、references/security-examples.md を参照してください

5.2 OWASP Top 10 との対応
カテゴリーリスク主な緩和策
A01 アクセス制御の不備HIGH権限の検証、デコレーター
A02 暗号化の失敗HIGHcryptography ライブラリー、Argon2
A03 インジェクションCRITICALパラメーター化クエリー、shell=True を使用しない
A04 安全でない設計MEDIUM型安全性、検証レイヤー
A05 セキュリティ設定のミスHIGH安全なデフォルト設定、依存関係の監査
A06 脆弱なコンポーネントHIGHCI で pip-audit、safety を使用
5.3 必須のセキュリティパターン
from pydantic import BaseModel, field_validator
import os, logging

# Secure base model - reject unknown fields, strip whitespace
class SecureInput(BaseModel):
    model_config = {'extra': 'forbid', 'str_strip_whitespace': True}

    @field_validator('*', mode='before')
    @classmethod
    def reject_null_bytes(cls, v):
        if isinstance(v, str) and '\x00' in v:
            raise ValueError('Null bytes not allowed')
        return v

# Secrets from environment (NEVER hardcode)
API_KEY = os.environ["API_KEY"]
DB_URL = os.environ["DATABASE_URL"]

# Safe error handling - log details, return safe message
class AppError(Exception):
    def __init__(self, message: str, internal: str = None):
        self.message = message
        if internal:
            logging.error(f"{message}: {internal}")

    def to_response(self) -> dict:
        return {"error": self.message}

シークレットマネージャーとの統合については、references/advanced-patterns.md を参照してください


6. テストと検証

セキュリティテストコマンド
bandit -r src/ -ll          # Static analysis
pip-audit && safety check   # Dependency vulnerabilities
mypy src/ --strict          # Type checking
セキュリティテストの例
import pytest
from pathlib import Path

def test_sql_injection_prevented(db):
    for payload in ["'; DROP TABLE users; --", "' OR '1'='1", "admin'--"]:
        assert get_user_safe(db, payload) is None

def test_path_traversal_blocked():
    base = Path("/app/data")
    for attack in ["../etc/passwd", "..\\windows\\system32", "foo/../../etc/passwd"]:
        with pytest.raises(ValueError, match="traversal|Invalid"):
            safe_read_file(base, attack)

def test_command_injection_blocked():
    with pytest.raises(ValueError, match="not allowed"):
        run_command_safe("rm", ["-rf", "/"])

包括的なテストパターンについては、references/security-examples.md を参照してください


7. よくある間違いとアンチパターン

アンチパターン悪い例良い例
SQL のフォーマットf"SELECT * WHERE id={id}"select(User).where(User.id == id)
信頼できない picklepickle.loads(data)json.loads(data)
シェルインジェクションsubprocess.run(f"echo {x}", shell=True)subprocess.run(["echo", x])
弱いハッシュhashlib.md5(pw).hexdigest()PasswordHasher().hash(pw)
シークレットのハードコードAPI_KEY = "sk-123..."API_KEY = os.environ["API_KEY"]

8. デプロイ前チェックリスト

フェーズ 1:コードを書く前
  • 要件を理解し、文書化している
  • API 設計をレビューしている(入力、出力、エラー)
  • セキュリティ脅威モデルを検討している
  • テストケースを先に作成している(TDD)
  • エッジケースとエラーシナリオを特定している
フェーズ 2:実装中
  • TDD ワークフローに従っている(テスト -> 実装 -> リファクタリング)
  • パフォーマンスパターンを使用している(非同期、ジェネレーター、プーリング)
  • すべての入力を Pydantic で検証している
  • DB クエリーをパラメーター化している/ORM を使用している
  • ファイル操作でパスの包含関係を確認している
  • サブプロセスでリスト形式の引数を使用している
  • パスワードを Argon2id でハッシュ化している
  • シークレットを環境変数からのみ取得している
フェーズ 3:コミット前
  • すべてのテストが成功する:pytest --cov=src
  • 型チェックが成功する:mypy src/ --strict
  • セキュリティスキャンが成功する:bandit -r src/ -ll
  • 依存関係の監査が成功する:pip-audit && safety check
  • コード内にハードコードされたシークレットがない
  • エラーから内部の詳細情報が漏えいしない
  • デバッグモードが無効になっている
  • ロギングが設定されている(PII/シークレットを含めない)

9. まとめ

型安全で、セキュアで、テスト可能かつ保守しやすいPython コードを作成してください。

セキュリティの基本:

  1. すべてのユーザー入力を検証し、サニタイズする
  2. データベース操作にはパラメーター化クエリーを使用する
  3. ユーザー入力に対して shell=True を決して使用しない
  4. パスワードを Argon2id でハッシュ化する
  5. シークレットを環境変数から読み込む
  6. 依存関係を最新の状態に保ち、監査する

攻撃シナリオと脅威モデリングについては、references/threat-model.md を参照してください

コメント