mcpField
S
security

security

github.com/alexanderstephenthompsonセキュリティ36 回インストール
リポジトリ

security について

ユーザーデータ、認証、外部入力を扱うエージェントや開発者向けのセキュリティ標準スキルです。安全なコーディングの指針、実装・レビュー用チェックリスト、検査ルール、シークレットと依存関係の確認スクリプトを備えています。

主な機能

  1. 01入力検証とインジェクション対策
  2. 02認証と認可の指針
  3. 03データ保護とシークレット管理
  4. 04API、アップロード、ログの保護
  5. 05実装・コードレビュー用チェックリスト
  6. 06ルールとセキュリティスキャンスクリプト

活用シーン

  1. 01実装前のセキュリティ計画
  2. 02コードのセキュリティ違反のレビュー
  3. 03リポジトリ内のシークレットと脆弱な依存関係の確認

インストール

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

$npx skills add https://github.com/alexanderstephenthompson/claude-hub --skill security

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

同梱ファイル

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

assets/
threat-model-template.md
security-checklist.md
references/
owasp-top-10.md
input-validation.md
auth-patterns.md
scripts/
scan_secrets.py
check_dependencies.py

詳細

セキュリティスキル

バージョン: 1.0 ソース: セキュリティ標準

セキュリティは後から付け足すのではなく、最初から組み込む必要があります。これらの標準は、ユーザーデータ、認証、または外部入力を扱うすべてのコードに適用されます。

問題点

AI エージェントは、安全にコードを作ることよりも、コードを動作させることを優先しがちです。明確なセキュリティ標準がなければ、各セッションでは最短の道が選ばれます。たとえば、クエリの文字列連結、手軽さを優先したシークレットのハードコード、速度を重視した広範な権限付与です。これらは悪意のある選択ではありません。セキュリティがプロンプトに含まれていないとき、最も抵抗の少ない道だからです。これらの標準により、安全なパターンがデフォルトになります。

活用方法

  • ビルダー: ユーザー入力、認証、または外部サービスに関わるコードを書く前に、## ビルダー向けチェックリスト を読んでください。セキュリティは設計段階で組み込む必要があり、後から修正するものではありません。
  • リファクタリング担当者: ## 適用ルール を使って、セキュリティ違反を見つけてください。修正方法については、説明セクションを読んでください。
  • 両者: 説明セクションが正式な標準です。チェックリストとルール表は、同じ内容を簡潔にまとめたものです。

基本原則

  1. セキュリティ・バイ・デザイン — 後付けではなく、最初からセキュリティを組み込む
  2. 多層防御 — セキュリティ対策を多層化し、単一障害点をなくす
  3. 最小権限 — タスクに必要な最小限のアクセス権を付与する
  4. 安全なフェイル — エラーによって脆弱性や機密データを露呈させない
  5. ゼロトラスト — 入力を決して信頼せず、常に検証する
  6. 侵害を前提とする — 攻撃者が侵入することを想定して設計し、被害範囲を最小限に抑える

OWASP Top 10(2021)

防止すべき重大な脆弱性:

#脆弱性防止策
1アクセス制御の不備すべてのリクエストで認可を確認する
2暗号化の失敗強力な暗号化を使用し、独自の方式を作らない
3インジェクションパラメーター化クエリ、入力検証
4安全でない設計脅威モデリング、安全なアーキテクチャ
5セキュリティ設定の不備安全なデフォルト設定、適切なエラー処理
6脆弱なコンポーネント依存関係を最新に保ち、定期的に監査する
7認証の失敗強力な認証、多要素認証(MFA)、安全なセッション管理
8完全性の失敗コード/データの完全性を検証し、リリースに署名する
9ログ記録の失敗セキュリティイベントを記録し、ログデータを保護する
10SSRFサーバー側の URL を検証し、許可リストを使用する

入力検証

基本原則

ユーザー入力を決して信頼しないでください。 すべての入力は悪意のあるものである可能性があります。

検証戦略
1. Validate → 2. Sanitize → 3. Encode (for output context)
SQL インジェクションの防止
# ❌ NEVER - String concatenation
query = f"SELECT * FROM users WHERE id = {user_id}"

# ✅ ALWAYS - Parameterized queries
cursor.execute("SELECT * FROM users WHERE id = ?", (user_id,))

# ✅ ALWAYS - ORM with parameters
User.objects.filter(id=user_id)
XSS の防止
// ❌ NEVER - Direct HTML insertion
element.innerHTML = userInput;
document.write(userInput);

// ✅ ALWAYS - Text content (auto-escapes)
element.textContent = userInput;

// ✅ ALWAYS - Template literals with escaping
const escaped = escapeHtml(userInput);
コマンドインジェクションの防止
# ❌ NEVER - Shell execution with user input
os.system(f"ls {user_path}")
subprocess.call(f"convert {filename}", shell=True)

# ✅ ALWAYS - Argument arrays (no shell)
subprocess.run(["ls", user_path], shell=False)
subprocess.run(["convert", filename], shell=False)
入力検証のパターン
import re

def validate_email(email: str) -> bool:
    """Validate email format."""
    pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
    return bool(re.match(pattern, email)) and len(email) <= 254

def validate_username(username: str) -> bool:
    """Validate username: alphanumeric, 3-30 chars."""
    pattern = r'^[a-zA-Z0-9_]{3,30}$'
    return bool(re.match(pattern, username))

def validate_url(url: str, allowed_domains: list[str]) -> bool:
    """Validate URL against allowlist."""
    from urllib.parse import urlparse
    parsed = urlparse(url)
    return (
        parsed.scheme in ('http', 'https') and
        parsed.netloc in allowed_domains
    )

認証と認可

パスワード要件
要件最低基準
長さ12 文字
複雑さ長さの要件を満たす場合は不要
よく使われるパスワード上位 10,000 件をブロックする
漏えいしたパスワードHaveIBeenPwned と照合する
パスワードの保存
# ✅ Use bcrypt, Argon2, or scrypt
import bcrypt

def hash_password(password: str) -> bytes:
    """Hash password with bcrypt."""
    salt = bcrypt.gensalt(rounds=12)
    return bcrypt.hashpw(password.encode(), salt)

def verify_password(password: str, hashed: bytes) -> bool:
    """Verify password against hash."""
    return bcrypt.checkpw(password.encode(), hashed)

絶対にしないでください:

  • パスワードを平文で保存する
  • パスワードに MD5 または SHA1 を使用する
  • 独自のハッシュ方式を作る
セッション管理
# Session security settings
SESSION_CONFIG = {
    "cookie_secure": True,      # HTTPS only
    "cookie_httponly": True,    # No JavaScript access
    "cookie_samesite": "Lax",   # CSRF protection
    "session_lifetime": 3600,   # 1 hour max
    "regenerate_on_login": True # Prevent session fixation
}
認可チェック
# ✅ Check authorization on EVERY request
def get_document(user, document_id):
    document = Document.get(document_id)

    # Always verify ownership/access
    if document.owner_id != user.id and not user.is_admin:
        raise PermissionError("Access denied")

    return document

データ保護

暗号化要件
データの種類保存時転送中
パスワードハッシュ化(bcrypt/Argon2)TLS 1.2+
個人を特定できる情報(名前、メールアドレス、住所)AES-256TLS 1.2+
支払いデータAES-256 + PCI DSSTLS 1.3
健康データAES-256 + HIPAATLS 1.3
セッショントークン該当なしTLS 1.2+
API キーAES-256TLS 1.2+
機密データの取り扱い
# ✅ Mask sensitive data in logs
def log_user_action(user, action, data):
    safe_data = {
        "user_id": user.id,
        "email": mask_email(user.email),  # j***@example.com
        "action": action,
        # Never log: passwords, tokens, full credit cards
    }
    logger.info("User action", extra=safe_data)

def mask_email(email: str) -> str:
    """Mask email for logging."""
    local, domain = email.split("@")
    return f"{local[0]}***@{domain}"

def mask_card(card: str) -> str:
    """Show only last 4 digits."""
    return f"****-****-****-{card[-4:]}"
データ保持
  • 不要になったデータを削除する
  • データの有効期限ポリシーを実装する
  • ユーザーデータのエクスポート/削除を可能にする(GDPR)
  • 削除済みデータを安全に消去する(削除済みとしてマークするだけでは不十分)

API セキュリティ

レート制限
# Implement rate limiting per endpoint
RATE_LIMITS = {
    "/api/login": "5/minute",      # Prevent brute force
    "/api/register": "3/minute",   # Prevent spam
    "/api/password-reset": "3/hour",
    "/api/*": "100/minute",        # General limit
}
CORS 設定
# ✅ Specific origins only
CORS_CONFIG = {
    "origins": [
        "https://app.example.com",
        "https://admin.example.com",
    ],
    "methods": ["GET", "POST", "PUT", "DELETE"],
    "allow_credentials": True,
    "max_age": 3600,
}

# ❌ NEVER in production
CORS_CONFIG = {
    "origins": "*",  # Allows any origin!
}
API レスポンスのセキュリティ
# ❌ Never expose internal errors
def handle_error(error):
    # Don't send: stack traces, SQL errors, file paths
    return {"error": "An error occurred"}, 500

# ✅ Log details, return generic message
def handle_error(error):
    logger.error(f"Internal error: {error}", exc_info=True)
    return {"error": "Internal server error"}, 500
セキュリティヘッダー
SECURITY_HEADERS = {
    "Strict-Transport-Security": "max-age=31536000; includeSubDomains",
    "X-Content-Type-Options": "nosniff",
    "X-Frame-Options": "DENY",
    "X-XSS-Protection": "1; mode=block",
    "Content-Security-Policy": "default-src 'self'",
    "Referrer-Policy": "strict-origin-when-cross-origin",
}

シークレット管理

環境変数
# ✅ Store secrets in environment
export DATABASE_URL="postgres://..."
export API_KEY="..."
export JWT_SECRET="..."

# ❌ NEVER commit secrets to code
DATABASE_URL = "postgres://user:password@host/db"  # In code!
シークレットの要件
シークレットの種類ローテーション期間保存場所
API キー90 日Vault/環境変数
データベースのパスワード90 日Vault/環境変数
JWT シークレット30 日Vault/環境変数
暗号化キー1 年HSM/KMS
ユーザーのパスワード漏えい時DB にハッシュ化して保存
.gitignore
# Secrets - NEVER commit
.env
.env.local
.env.*.local
*.pem
*.key
credentials.json
secrets.yaml
config/secrets/*

ファイルアップロードのセキュリティ

検証チェックリスト
def validate_upload(file) -> bool:
    """Validate uploaded file."""

    # 1. Check file size
    MAX_SIZE = 10 * 1024 * 1024  # 10MB
    if file.size > MAX_SIZE:
        raise ValueError("File too large")

    # 2. Check extension against allowlist
    ALLOWED_EXTENSIONS = {'.jpg', '.jpeg', '.png', '.pdf'}
    ext = Path(file.name).suffix.lower()
    if ext not in ALLOWED_EXTENSIONS:
        raise ValueError("File type not allowed")

    # 3. Verify magic bytes (don't trust extension)
    magic_bytes = file.read(8)
    file.seek(0)
    if not is_valid_magic(magic_bytes, ext):
        raise ValueError("File content doesn't match extension")

    # 4. Generate safe filename
    safe_name = generate_safe_filename(file.name)

    # 5. Store outside web root
    storage_path = UPLOAD_DIR / safe_name  # Not in /public!

    return True
安全なファイル名の生成
import uuid
import re
from pathlib import Path

def generate_safe_filename(original: str) -> str:
    """Generate safe filename, preserving extension."""
    ext = Path(original).suffix.lower()
    # Use UUID, not original filename
    return f"{uuid.uuid4()}{ext}"

ロギングとモニタリング

ログに記録する内容
# ✅ Log these security events
SECURITY_EVENTS = [
    "login_success",
    "login_failure",
    "logout",
    "password_change",
    "password_reset_request",
    "permission_denied",
    "invalid_token",
    "rate_limit_exceeded",
    "suspicious_input",
    "admin_action",
]
ログに記録しない内容
# ❌ NEVER log these
NEVER_LOG = [
    "password",
    "password_hash",
    "credit_card",
    "ssn",
    "api_key",
    "session_token",
    "jwt_token",
    "private_key",
]
構造化されたセキュリティログ
def log_security_event(event_type: str, user_id: str, details: dict):
    """Log security event with context."""
    logger.info("security_event", extra={
        "event_type": event_type,
        "user_id": user_id,
        "timestamp": datetime.utcnow().isoformat(),
        "ip_address": get_client_ip(),
        "user_agent": get_user_agent(),
        **sanitize_details(details),
    })

ビルダーチェックリスト

ユーザーデータ、認証、または外部入力を扱うコードを書く前に、これらの制約に照らして計画を確認してください。ビルダーはコードを書く前にこのセクションを読み、リファクタリング担当者は「適用されるルール」表と詳細な説明を使用します。

リリース前に毎回確認すること
  • コードやバージョン管理システムにシークレットが含まれていない
  • すべてのユーザー入力が検証およびサニタイズされている
  • SQL クエリでパラメーター化されたステートメントを使用している
  • 保護対象のすべてのエンドポイントで認証を実施している
  • すべてのリソースに対して認可チェックを実施している
  • HTTPS を強制している(HTTP は使用しない)
  • セキュリティヘッダーを設定している
  • レート制限を導入している
  • エラーメッセージから機密情報が漏えいしない
  • 依存関係を更新し、監査している
  • ファイルアップロードを検証し、安全に保存している
  • ログにセキュリティイベントを記録している
  • CORS を厳格に設定している
コードレビューで重点的に確認するセキュリティ項目
  • すべての入力箇所で入力検証を行っている
  • XSS 防止のために出力をエンコードしている
  • アクセス制御チェックを実施している
  • ハードコードされたシークレットがない
  • 適切なエラー処理を行っている(スタックトレースを表示しない)
  • 安全なデフォルト設定を使用している
  • サードパーティライブラリが必要であり、信頼できる

適用されるルール

これらのルールは check.js (clean-team) によって決定論的にチェックされます。これらの基準を更新する場合は、対応する check.js のルールも同様に更新してください。その逆も同様です。

ルール ID重大度チェック内容
no-document-writeエラーdocument.write() の使用(DOM インジェクションのリスク)
no-hardcoded-secretsエラー文字列リテラル内の API キー、トークン、パスワード
no-innerHTML警告.innerHTML の代入(XSS のリスク)

参考資料

  • references/owasp-top-10.md — OWASP の脆弱性に関する詳細ガイド
  • references/input-validation.md — 入力検証パターンの完全版
  • references/auth-patterns.md — 認証および認可のパターン

アセット

  • assets/security-checklist.md — リリース前のセキュリティチェックリスト
  • assets/threat-model-template.md — 脅威モデリングのテンプレート

スクリプト

  • scripts/scan_secrets.py — 誤ってコミットされたシークレットがないかコードをスキャンします
  • scripts/check_dependencies.py — 既知の脆弱性がないか依存関係をチェックします

コメント