147 lines
7.0 KiB
Django/Jinja
147 lines
7.0 KiB
Django/Jinja
<broken_function_level_authorization_guide>
|
||
<title>BROKEN FUNCTION LEVEL AUTHORIZATION (BFLA)</title>
|
||
|
||
<critical>BFLA is action-level authorization failure: callers invoke functions (endpoints, mutations, admin tools) they are not entitled to. It appears when enforcement differs across transports, gateways, roles, or when services trust client hints. Bind subject × action at the service that performs the action.</critical>
|
||
|
||
<scope>
|
||
- Vertical authz: privileged/admin/staff-only actions reachable by basic users
|
||
- Feature gates: toggles enforced at edge/UI, not at core services
|
||
- Transport drift: REST vs GraphQL vs gRPC vs WebSocket with inconsistent checks
|
||
- Gateway trust: backends trust X-User-Id/X-Role injected by proxies/edges
|
||
- Background workers/jobs performing actions without re-checking authz
|
||
</scope>
|
||
|
||
<methodology>
|
||
1. Build an Actor × Action matrix with at least: unauth, basic, premium, staff/admin. Enumerate actions (create/update/delete, approve/cancel, impersonate, export, invite, role-change, credit/refund).
|
||
2. Obtain tokens/sessions for each role. Exercise every action across all transports and encodings (JSON, form, multipart), including method overrides.
|
||
3. Vary headers and contextual selectors (org/tenant/project) and test behavior behind gateway vs direct-to-service.
|
||
4. Include background flows: job creation/finalization, webhooks, queues. Confirm re-validation of authz in consumers.
|
||
</methodology>
|
||
|
||
<discovery_techniques>
|
||
<surface_enumeration>
|
||
- Admin/staff consoles and APIs, support tools, internal-only endpoints exposed via gateway
|
||
- Hidden buttons and disabled UI paths (feature-flagged) mapped to still-live endpoints
|
||
- GraphQL schemas: mutations and admin-only fields/types; gRPC service descriptors (reflection)
|
||
- Mobile clients often reveal extra endpoints/roles in app bundles or network logs
|
||
</surface_enumeration>
|
||
|
||
<signals>
|
||
- 401/403 on UI but 200 via direct API call; differing status codes across transports
|
||
- Actions succeed via background jobs when direct call is denied
|
||
- Changing only headers (role/org) alters access without token change
|
||
</signals>
|
||
|
||
<high_value_actions>
|
||
- Role/permission changes, impersonation/sudo, invite/accept into orgs
|
||
- Approve/void/refund/credit issuance, price/plan overrides
|
||
- Export/report generation, data deletion, account suspension/reactivation
|
||
- Feature flag toggles, quota/grant adjustments, license/seat changes
|
||
- Security settings: 2FA reset, email/phone verification overrides
|
||
</high_value_actions>
|
||
|
||
<exploitation_techniques>
|
||
<verb_drift_and_aliases>
|
||
- Alternate methods: GET performing state change; POST vs PUT vs PATCH differences; X-HTTP-Method-Override/_method
|
||
- Alternate endpoints performing the same action with weaker checks (legacy vs v2, mobile vs web)
|
||
</verb_drift_and_aliases>
|
||
|
||
<edge_vs_core_mismatch>
|
||
- Edge blocks an action but core service RPC accepts it directly; call internal service via exposed API route or SSRF
|
||
- Gateway-injected identity headers override token claims; supply conflicting headers to test precedence
|
||
</edge_vs_core_mismatch>
|
||
|
||
<feature_flag_bypass>
|
||
- Client-checked feature gates; call backend endpoints directly
|
||
- Admin-only mutations exposed but hidden in UI; invoke via GraphQL or gRPC tools
|
||
</feature_flag_bypass>
|
||
|
||
<batch_job_paths>
|
||
- Create export/import jobs where creation is allowed but finalize/approve lacks authz; finalize others' jobs
|
||
- Replay webhooks/background tasks endpoints that perform privileged actions without verifying caller
|
||
</batch_job_paths>
|
||
|
||
<content_type_paths>
|
||
- JSON vs form vs multipart handlers using different middleware: send the action via the most permissive parser
|
||
</content_type_paths>
|
||
</exploitation_techniques>
|
||
|
||
<advanced_techniques>
|
||
<graphql>
|
||
- Resolver-level checks per mutation/field; do not assume top-level auth covers nested mutations or admin fields
|
||
- Abuse aliases/batching to sneak privileged fields; persisted queries sometimes bypass auth transforms
|
||
- Example:
|
||
{% raw %}
|
||
mutation Promote($id:ID!){
|
||
a: updateUser(id:$id, role: ADMIN){ id role }
|
||
}
|
||
{% endraw %}
|
||
</graphql>
|
||
|
||
<grpc>
|
||
- Method-level auth via interceptors must enforce audience/roles; probe direct gRPC with tokens of lower role
|
||
- Reflection lists services/methods; call admin methods that the gateway hid
|
||
</grpc>
|
||
|
||
<websocket>
|
||
- Handshake-only auth: ensure per-message authorization on privileged events (e.g., admin:impersonate)
|
||
- Try emitting privileged actions after joining standard channels
|
||
</websocket>
|
||
|
||
<multi_tenant>
|
||
- Actions requiring tenant admin enforced only by header/subdomain; attempt cross-tenant admin actions by switching selectors with same token
|
||
</multi_tenant>
|
||
|
||
<microservices>
|
||
- Internal RPCs trust upstream checks; reach them through exposed endpoints or SSRF; verify each service re-enforces authz
|
||
</microservices>
|
||
|
||
<bypass_techniques>
|
||
<header_trust>
|
||
- Supply X-User-Id/X-Role/X-Organization headers; remove or contradict token claims; observe which source wins
|
||
</header_trust>
|
||
|
||
<route_shadowing>
|
||
- Legacy/alternate routes (e.g., /admin/v1 vs /v2/admin) that skip new middleware chains
|
||
</route_shadowing>
|
||
|
||
<idempotency_and_retries>
|
||
- Retry or replay finalize/approve endpoints that apply state without checking actor on each call
|
||
</idempotency_and_retries>
|
||
|
||
<cache_key_confusion>
|
||
- Cached authorization decisions at edge leading to cross-user reuse; test with Vary and session swaps
|
||
</cache_key_confusion>
|
||
</bypass_techniques>
|
||
|
||
<validation>
|
||
1. Show a lower-privileged principal successfully invokes a restricted action (same inputs) while the proper role succeeds and another lower role fails.
|
||
2. Provide evidence across at least two transports or encodings demonstrating inconsistent enforcement.
|
||
3. Demonstrate that removing/altering client-side gates (buttons/flags) does not affect backend success.
|
||
4. Include durable state change proof: before/after snapshots, audit logs, and authoritative sources.
|
||
</validation>
|
||
|
||
<false_positives>
|
||
- Read-only endpoints mislabeled as admin but publicly documented
|
||
- Feature toggles intentionally open to all roles for preview/beta with clear policy
|
||
- Simulated environments where admin endpoints are stubbed with no side effects
|
||
</false_positives>
|
||
|
||
<impact>
|
||
- Privilege escalation to admin/staff actions
|
||
- Monetary/state impact: refunds/credits/approvals without authorization
|
||
- Tenant-wide configuration changes, impersonation, or data deletion
|
||
- Compliance and audit violations due to bypassed approval workflows
|
||
</impact>
|
||
|
||
<pro_tips>
|
||
1. Start from the role matrix; test every action with basic vs admin tokens across REST/GraphQL/gRPC.
|
||
2. Diff middleware stacks between routes; weak chains often exist on legacy or alternate encodings.
|
||
3. Inspect gateways for identity header injection; never trust client-provided identity.
|
||
4. Treat jobs/webhooks as first-class: finalize/approve must re-check the actor.
|
||
5. Prefer minimal PoCs: one request that flips a privileged field or invokes an admin method with a basic token.
|
||
</pro_tips>
|
||
|
||
<remember>Authorization must bind the actor to the specific action at the service boundary on every request and message. UI gates, gateways, or prior steps do not substitute for function-level checks.</remember>
|
||
</broken_function_level_authorization_guide>
|