Files
strix/strix/prompts/technologies/firebase_firestore.jinja
2025-10-18 18:39:39 -07:00

178 lines
11 KiB
Django/Jinja
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<firebase_firestore_security_guide>
<title>FIREBASE / FIRESTORE — ADVERSARIAL TESTING AND EXPLOITATION</title>
<critical>Most impactful findings in Firebase apps arise from weak Firestore/Realtime Database rules, Cloud Storage exposure, callable/onRequest Functions trusting client input, incorrect ID token validation, and over-trusted App Check. Treat every client-supplied field and token as untrusted. Bind subject/tenant on the server, not in the client.</critical>
<scope>
- Firestore (documents/collections, rules, REST/SDK)
- Realtime Database (JSON tree, rules)
- Cloud Storage (rules, signed URLs)
- Auth (ID tokens, custom claims, anonymous/sign-in providers)
- Cloud Functions (onCall/onRequest, triggers)
- Hosting rewrites, CDN/caching, CORS
- App Check (attestation) and its limits
</scope>
<methodology>
1. Extract project config from client (apiKey, authDomain, projectId, appId, storageBucket, messagingSenderId). Identify all used Firebase products.
2. Obtain multiple principals: unauth, anonymous (if enabled), basic user A, user B, and any staff/admin if available. Capture their ID tokens.
3. Build Resource × Action × Principal matrix across Firestore/Realtime/Storage/Functions. Exercise every action via SDK and raw REST (googleapis) to detect parity gaps.
4. Start from list/query paths (where allowed) to seed IDs; then swap document paths, tenants, and user IDs across principals and transports.
</methodology>
<architecture>
- Firestore REST: https://firestore.googleapis.com/v1/projects/<project>/databases/(default)/documents/<path>
- Storage REST: https://storage.googleapis.com/storage/v1/b/<bucket>
- Auth: Google-signed ID tokens (iss accounts.google.com/securetoken.google.com/<project>), aud <project/app-id>; identity is in sub/uid.
- Rules engines: separate for Firestore, Realtime DB, and Storage; Functions bypass rules when using Admin SDK.
</architecture>
<auth_and_tokens>
- ID token verification must enforce issuer, audience (project), signature (Google JWKS), expiration, and optionally App Check binding when used.
- Custom claims are appended by Admin SDK; client-supplied claims are ignored by Auth but may be trusted by app code if copied into docs.
- Pitfalls:
- Accepting any JWT with valid signature but wrong audience/project.
- Trusting uid/account IDs from request body instead of context.auth.uid in Functions.
- Mixing session cookies and ID tokens without verifying both paths equivalently.
- Tests:
- Replay tokens across environments/projects; expect strict aud/iss rejection server-side.
- Call Functions with and without Authorization; verify identical checks on both onCall and onRequest variants.
</auth_and_tokens>
<firestore_rules>
- Rules are not filters: a query must include constraints that make the rule true for all returned documents; otherwise reads fail. Do not rely on client to include where clauses correctly.
- Prefer ownership derived from request.auth.uid and server data, not from client payload fields.
- Common gaps:
- allow read: if request.auth != null (any user reads all data)
- allow write: if request.auth != null (mass write)
- Missing per-field validation (adds isAdmin/role/tenantId fields).
- Using client-supplied ownerId/orgId instead of enforcing doc.ownerId == request.auth.uid or membership in org.
- Over-broad list rules on root collections; per-doc checks exist but list still leaks via queries.
- Validation patterns:
- Restrict writes: request.resource.data.keys().hasOnly([...]) and forbid privilege fields.
- Enforce ownership: resource.data.ownerId == request.auth.uid && request.resource.data.ownerId == request.auth.uid
- Org membership: exists(/databases/(default)/documents/orgs/$(org)/members/$(request.auth.uid))
- Tests:
- Compare results for users A/B on identical queries; diff counts and IDs.
- Attempt cross-tenant reads: where orgId == otherOrg; try queries without org filter to confirm denial.
- Write-path: set/patch with foreign ownerId/orgId; attempt to flip privilege flags.
</firestore_rules>
<firestore_queries>
- Enumerate via REST to avoid SDK client-side constraints; try structured and REST filters.
- Probe composite index requirements: UI-driven queries may hide missing rule coverage when indexes are enabled but rules are broad.
- Explore collection group queries (collectionGroup) that may bypass per-collection rules if not mirrored.
- Use startAt/endAt/in/array-contains to probe rule edges and pagination cursors for cross-tenant bleed.
</firestore_queries>
<realtime_database>
- Misconfigured rules frequently expose entire JSON trees. Probe https://<project>.firebaseio.com/.json with and without auth.
- Confirm rules for read/write use auth.uid and granular path checks; avoid .read/.write: true or auth != null at high-level nodes.
- Attempt to write privilege-bearing nodes (roles, org membership) and observe downstream effects (e.g., Cloud Functions triggers).
</realtime_database>
<cloud_storage>
- Rules parallel Firestore but apply to object paths. Common issues:
- Public reads on sensitive buckets/paths.
- Signed URLs with long TTL, no content-disposition controls; replayable across tenants.
- List operations exposed: /o?prefix= enumerates object keys.
- Tests:
- GET gs:// paths via https endpoints without auth; verify content-type and Content-Disposition: attachment.
- Generate and reuse signed URLs across accounts and paths; try case/URL-encoding variants.
- Upload HTML/SVG and verify X-Content-Type-Options: nosniff; check for script execution.
</cloud_storage>
<cloud_functions>
- onCall provides context.auth automatically; onRequest must verify ID tokens explicitly. Admin SDK bypasses rules; all ownership/tenant checks must be enforced in code.
- Common gaps:
- Trusting client uid/orgId from request body instead of context.auth.
- Missing aud/iss verification when manually parsing tokens.
- Over-broad CORS allowing credentialed cross-origin requests; echoing Authorization in responses.
- Triggers (onCreate/onWrite) granting roles or issuing signed URLs solely based on document content controlled by the client.
- Tests:
- Call both onCall and equivalent onRequest endpoints with varied tokens and bodies; expect identical decisions.
- Create crafted docs to trigger privilege-granting functions; verify that server re-derives subject/tenant before acting.
- Attempt internal fetches (SSRF) via Functions to project/metadata endpoints.
</cloud_functions>
<app_check>
- App Check is not a substitute for authorization. Many apps enable App Check enforcement on client SDKs but do not verify on custom backends.
- Bypasses:
- Unenforced paths: REST calls directly to googleapis endpoints with ID token succeed regardless of App Check.
- Mobile reverse engineering: hook client and reuse ID token flows without attestation.
- Tests:
- Compare SDK vs REST behavior with/without App Check headers; confirm no elevated authorization via App Check alone.
</app_check>
<tenant_isolation>
- Apps often implement multi-tenant data models (orgs/<orgId>/...). Bind tenant from server context (membership doc or custom claim), not from client payload.
- Tests:
- Vary org header/subdomain/query while keeping token fixed; verify server denies cross-tenant access.
- Export/report Functions: ensure queries execute under caller scope; signed outputs must encode tenant and short TTL.
</tenant_isolation>
<bypass_techniques>
- Content-type switching: JSON vs form vs multipart to hit alternate code paths in onRequest Functions.
- Parameter/field pollution: duplicate JSON keys; last-one-wins in many parsers; attempt to sneak privilege fields.
- Caching/CDN: Hosting rewrites or proxies that key responses without Authorization or tenant headers.
- Race windows: write then read before background enforcements (e.g., post-write claim synchronizations) complete.
</bypass_techniques>
<blind_channels>
- Firestore: use error shape, document count, and ETag/length to infer existence under partial denial.
- Storage: length/timing differences on signed URL attempts leak validity.
- Functions: constant-time comparisons vs variable messages reveal authorization branches.
</blind_channels>
<tooling_and_automation>
- SDK + REST: httpie/curl + jq for REST; Firebase emulator and Rules Playground for rapid iteration.
- Mobile: apktool/objection/frida to extract config and hook SDK calls; inspect network logs for endpoints and tokens.
- Rules analysis: script rule probes for common patterns (auth != null, missing field validation, list vs get parity).
- Functions: fuzz onRequest endpoints with varied content-types and missing/forged Authorization; verify CORS and token handling.
- Storage: enumerate prefixes; test signed URL generation and reuse patterns.
</tooling_and_automation>
<reviewer_checklist>
- Do Firestore/Realtime/Storage rules derive subject and tenant from auth, not client fields?
- Are list/query rules aligned with per-doc checks (no broad list leaks)?
- Are privilege-bearing fields immutable or server-only (forbidden in writes)?
- Do Functions verify ID tokens (iss/aud/exp/signature) and re-derive identity before acting?
- Are Admin SDK operations scoped by server-side checks (ownership/tenant)?
- Is App Check treated as advisory, not authorization, across all paths?
- Are Hosting/CDN cache keys bound to Authorization/tenant to prevent leaks?
</reviewer_checklist>
<validation>
1. Provide owner vs non-owner Firestore queries showing unauthorized access or metadata leak.
2. Demonstrate Cloud Storage read/write beyond intended scope (public object, signed URL reuse, or list exposure).
3. Show a Function accepting forged/foreign identity (wrong aud/iss) or trusting client uid/orgId.
4. Document minimal reproducible requests with roles/tokens used and observed deltas.
</validation>
<false_positives>
- Public collections/objects documented and intended.
- Rules that correctly enforce per-doc checks with matching query constraints.
- Functions verifying tokens and ignoring client-supplied identifiers.
- App Check enforced but not relied upon for authorization.
</false_positives>
<impact>
- Cross-account and cross-tenant data exposure.
- Unauthorized state changes via Functions or direct writes.
- Exfiltration of PII/PHI and private files from Storage.
- Durable privilege escalation via misused custom claims or triggers.
</impact>
<pro_tips>
1. Treat apiKey as project identifier only; identity must come from verified ID tokens.
2. Start from rules: read them, then prove gaps with diffed owner/non-owner requests.
3. Prefer REST for parity checks; SDKs can mask errors via client-side filters.
4. Hunt privilege fields in docs and forbid them via rules; verify immutability.
5. Probe collectionGroup queries and list rules; many leaks live there.
6. Functions are the authority boundary—enforce subject/tenant there even if rules exist.
7. Keep concise PoCs: one owner vs non-owner request per surface that clearly demonstrates the unauthorized delta.
</pro_tips>
<remember>Authorization must hold at every layer: rules, Functions, and Storage. Bind subject and tenant from verified tokens and server data, never from client payload or UI assumptions. Any gap becomes a cross-account or cross-tenant vulnerability.</remember>
</firebase_firestore_security_guide>