mcpField
B
broken-access-control

broken-access-control

github.com/scholarly360セキュリティ2252 回インストール29 週間前に更新
リポジトリ

broken-access-control について

PythonのWebアプリを対象に、アクセス制御の不備を調べるセキュリティ監査スキルです。認可漏れ、IDOR、CORS、SSRF、CSRF、JWTとセッションの安全性を扱い、監査手順とスキャン方法を示します。

主な機能

  1. 01ルートの認可と権限チェックの確認
  2. 02リソース所有権の検証によるIDOR検出
  3. 03CORSとSSRFリスクの確認
  4. 04CSRF、JWT、セッション設定の点検
  5. 05BanditとOWASP ZAPのスキャン案内

活用シーン

  1. 01FastAPIまたはFlaskアプリの監査
  2. 02ユーザーリソースへの不正アクセス確認
  3. 03CORS設定とユーザー指定URLのリスク調査

インストール

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

$npx skills add https://github.com/scholarly360/owasp-top10-web-skills --skill broken-access-control

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

同梱ファイルreferences/bac-detail.md

詳細

アクセス制御の不備(A01:2025)

2回連続でOWASPリスクの第1位です。 アプリケーションの3.74%で発見され、180万件以上の発生と32,654件のCVEが報告されています。アクセス制御は、ユーザーが意図された権限の範囲を超えて操作できないようにします。不備があると、データの不正な開示、改ざん、破壊につながります。

すべてのCWEと修正パターンの詳しい資料については、references/bac-detail.mdを参照してください。


このスキルの対象範囲

サブカテゴリー説明主なCWE
認可の欠如認証ガードのないルート/エンドポイントCWE-862, CWE-284
IDORリソースの所有者が検証されていないCWE-639, CWE-285
CORSの設定ミスワイルドカードまたは過度に許可的なオリジンCWE-284
SSRF内部/プライベートIPへのアウトバウンドリクエストCWE-918
CSRF状態を変更するフォームにトークン検証がないCWE-352
権限昇格ユーザーがより高い権限のロールにアクセスするCWE-269
JWT/セッションの改ざんメタデータの改ざん、セッション固定化CWE-287

ワークフロー:FastAPIまたはFlaskアプリの監査

ステップ1 — すべてのルートを特定する

FastAPI:

# List all routes and their dependencies
for route in app.routes:
    print(route.path, route.methods, route.dependencies)

Flask:

# Print all registered endpoints
for rule in app.url_map.iter_rules():
    print(rule.endpoint, rule.methods, rule.rule)

次に該当するルートをすべて指摘してください。

  • 認証依存関係なしでPOST、PUT、PATCH、DELETEを処理する
  • 所有権を確認せずにユーザー固有のデータ(プロフィール、注文、ファイル)を返す
  • 機密性の高い操作にレート制限がない

ステップ2 — 認可ガードを確認する

FastAPI — Depends()の欠落を確認する:

# VULNERABLE — no auth check
@app.get("/users/{user_id}/data")
async def get_user_data(user_id: int):
    return db.query(UserData).filter_by(owner_id=user_id).all()

# SECURE — requires authenticated user
@app.get("/users/{user_id}/data")
async def get_user_data(user_id: int, current_user: User = Depends(get_current_user)):
    if current_user.id != user_id:
        raise HTTPException(status_code=403, detail="Forbidden")
    return db.query(UserData).filter_by(owner_id=user_id).all()

Flask — @login_requiredの欠落を確認する:

# VULNERABLE
@app.route("/dashboard")
def dashboard():
    return render_template("dashboard.html")

# SECURE
@app.route("/dashboard")
@login_required
def dashboard():
    return render_template("dashboard.html")

ステップ3 — IDORチェック(リソースの所有権)

IDORは、BACの不備で最もよく見られるものです。ユーザーが所有するリソースを取得するすべてのクエリで、resource.owner_idとcurrent_user.idを照合する必要があります。

# VULNERABLE IDOR — attacker can request any document_id
@app.get("/documents/{doc_id}")
async def get_doc(doc_id: int, user=Depends(get_current_user)):
    return db.get(Document, doc_id)  # No ownership check!

# SECURE
@app.get("/documents/{doc_id}")
async def get_doc(doc_id: int, user=Depends(get_current_user)):
    doc = db.get(Document, doc_id)
    if not doc or doc.owner_id != user.id:
        raise HTTPException(status_code=404)  # 404 preferred over 403 (avoids enumeration)
    return doc

テスト方法: ユーザーAとして認証し、リソースIDを記録した後、ユーザーBとして認証して同じIDをリクエストします。データを取得できた場合は、IDORです。


ステップ4 — CORSの設定ミス

FastAPI:

# VULNERABLE — wildcard origin
app.add_middleware(CORSMiddleware, allow_origins=["*"], allow_credentials=True)

# SECURE — explicit allowlist
app.add_middleware(
    CORSMiddleware,
    allow_origins=["https://app.yourdomain.com"],
    allow_credentials=True,
    allow_methods=["GET", "POST"],
    allow_headers=["Authorization", "Content-Type"],
)

Flask:

# VULNERABLE
CORS(app, origins="*")

# SECURE
CORS(app, origins=["https://app.yourdomain.com"], supports_credentials=True)

⚠️ allow_origins=["*"]とallow_credentials=Trueの組み合わせは二重に危険です。多くのブラウザーはこれをブロックしますが、深刻な設定ミスを示しています。


ステップ5 — SSRF(A01:2025の対象に追加)

ユーザーが制御するURLを使ってアウトバウンドHTTPリクエストを送信するコードをすべて確認してください。

import ipaddress, re

PRIVATE_RANGES = [
    ipaddress.ip_network("10.0.0.0/8"),
    ipaddress.ip_network("172.16.0.0/12"),
    ipaddress.ip_network("192.168.0.0/16"),
    ipaddress.ip_network("127.0.0.0/8"),
    ipaddress.ip_network("169.254.0.0/16"),  # AWS metadata
]

def is_safe_url(url: str) -> bool:
    from urllib.parse import urlparse
    import socket
    try:
        host = urlparse(url).hostname
        ip = ipaddress.ip_address(socket.gethostbyname(host))
        return not any(ip in net for net in PRIVATE_RANGES)
    except Exception:
        return False

# In your endpoint:
@app.post("/fetch")
async def fetch_url(url: str, user=Depends(get_current_user)):
    if not is_safe_url(url):
        raise HTTPException(status_code=400, detail="URL not allowed")
    return await httpx.get(url)

テスト方法: http://169.254.169.254/latest/meta-data/(AWSメタデータ)、http://localhost:6379(Redis)、http://10.0.0.1/admin


ステップ6 — CSRF(Flask固有のリスク)

JWT/Bearerトークンを使うFastAPI APIは、一般にCSRFの影響を受けません。セッションCookieを使うFlaskアプリには明示的な保護が必要です。

# Flask — verify Flask-WTF is installed and CSRF is enabled
from flask_wtf.csrf import CSRFProtect
csrf = CSRFProtect(app)

# All state-changing forms must include {{ form.hidden_tag() }} or {{ csrf_token() }}

設定でWTF_CSRF_ENABLED = Trueになっていることを確認してください(デフォルトで有効ですが、無効化されていないことを確認してください)。


ステップ7 — JWTとセッションのセキュリティ
# Verify JWT expiry is set (short-lived: 15 min–1 hr)
jwt.encode({"sub": user_id, "exp": datetime.utcnow() + timedelta(minutes=30)}, SECRET_KEY)

# Flask — verify session security flags
app.config["SESSION_COOKIE_SECURE"] = True    # HTTPS only
app.config["SESSION_COOKIE_HTTPONLY"] = True  # No JS access
app.config["SESSION_COOKIE_SAMESITE"] = "Lax" # CSRF mitigation
app.config["PERMANENT_SESSION_LIFETIME"] = timedelta(hours=2)

簡易監査チェックリスト

PythonのWebアプリを監査するときは、次の項目を確認してください。

  • すべての非公開ルートに認証依存関係/デコレーターがある
  • ユーザー所有リソースのクエリすべてでresource.owner_id == current_user.idを検証する
  • CORSオリジンが*ではなく、明示的な許可リストになっている
  • アウトバウンドHTTP呼び出しで、URLがプライベートIP範囲内でないことを検証する
  • Flaskアプリの、状態を変更するすべてのフォームでFlask-WTFのCSRF保護が有効になっている
  • JWTのexpクレームの有効期限が短く、セッションにSECURE、HTTPONLY、SAMESITEフラグが設定されている
  • ログアウト時にセッションIDが無効化される
  • アクセス制御の不備がログに記録され、アラートが発報される

自動スキャン

ツール検出対象コマンド
BanditSSRFのパターン、ハードコードされたシークレット、危険な関数bandit -r . -t B105,B106,B107,B501,B601
OWASP ZAPIDOR、実行時の認証の欠落、CORSzap-baseline.py -t http://localhost:8000
truffleHogGitの履歴に漏えいしたトークン/キーtrufflehog git file://. --only-verified

主要な CWE リファレンス

CWE名前典型的なパターン
CWE-284不適切なアクセス制御認証なしでルートにアクセスできる
CWE-285不適切な認可認証はあるが、ロールや所有権を確認していない
CWE-352CSRF状態を変更するエンドポイントが Cookie 認証を受け付け、CSRF トークンを要求しない
CWE-639ユーザー制御キーによる認証のバイパスIDOR — 所有権を確認せずに GET /orders/{id} を実行する
CWE-862認可の欠落@login_required または Depends(get_current_user) がない
CWE-918SSRF検証せずに requests.get(user_input_url) を実行する
CWE-200機密情報の漏えい認可されていないユーザーが他者の個人識別情報(PII)やデータを受け取る

関連項目

コメント