← Zurück zu Team für Next.js

Skill · Version 1.0.0

Serverseitige Richtlinien durchsetzen

Wendet dieselben Rechte auf Aktionen, Abfragen, Exporte und Hintergrundarbeit an und verweigert unklaren Kontext.

server-side-policy-enforcement

Teammitglieder mit diesem Skill

Entdecke, wie der Skill hilft

Wann ist der Skill hilfreich?

Nutze diesen Skill für tatsächlichen Schutz jenseits ausgeblendeter Schaltflächen.

Wobei hilft er dir?

  • Trennt Regelentscheidung von durchsetzenden Endpunkten.
  • Begrenzt Daten vor Seitennavigation und Aggregation.
  • Prüft einzelne Sammelziele und leitet UI-Hinweise aus Serverregeln ab.

Das könntest du fragen

Implementiere Angebotsfreigabe und Export mit gemeinsamen Policies samt gemischten Sammelrechten und fehlendem Arbeitsbereich. Mische erlaubte und verbotene Angebotskennungen in einer Sammelaktion. Wende den Teilfehlervertrag an; Exportsummen enthalten nur autorisierte Datensätze.

Ausführliche Dokumentation

Hier findest du die ursprüngliche Anleitung, Beispiele und Prüfschritte des Skills in ihrer Originalsprache.

Details…Weniger anzeigen

Server-Side Policy Enforcement

When to Use

Use when implementing or auditing authorization checks in API endpoints, GraphQL resolvers, RPC handlers, background jobs, data exports, and UI capability flags.

Core Principles (Saltzer & Schroeder)

1. Complete Mediation & Fail-Closed Defaults
  • UI Hiding Is UX, Never Security: Hiding an "Approve" or "Delete" button in the frontend only prevents accidental clicks. Every API mutation, query, export, and webhook/worker trigger must enforce the policy on the server.
  • Separate Policy Decision Point (PDP) from Policy Enforcement Point (PEP):
    • Keep business policy rules in dedicated, pure policy modules/gates (QuotePolicy.canApprove(actor, quote)), while controllers/handlers act as enforcement points (authorizeOrThrow(...)).
    • Derive UI capability hints (permissions: { canEdit: true, canApprove: false, reason: 'self_approval_forbidden' }) from the exact same server-side policy function so frontend button states and backend enforcement never drift apart.
  • Fail-Closed on Missing Context: If subject, tenant membership, or resource state is missing or ambiguous, deny access (DENY) by default.
2. Query-Level Scoping for Lists, Search, Aggregations & Exports

Checking permissions only on GET /items/:id leaves GET /items, search endpoints, dashboard totals, and CSV/PDF exports wide open!

  • Pair every record-level policy (canView(actor, record)) with a Query Scope Builder (scopeReadable(actor, queryBuilder)):
    • Example: If a sales rep may only see accounts in their assigned region (account.region_id IN (...) or account.owner_id = actor.id), apply that predicate directly in the SQL WHERE clause before COUNT(*), SUM(...), pagination, or CSV streaming.
  • Never fetch all rows into memory and filter them in application code after pagination (which breaks page sizes and leaks total counts).
3. Per-Item Enforcement on Bulk & Batch Operations

When an endpoint accepts an array of IDs (POST /quotes/bulk-archive { ids: [...] }):

  • Load and evaluate authorization for every individual target resource against its current database state and tenant ownership.
  • Never check only the first item or check only a coarse role (can('quote:archive')) while allowing the ID list to include records owned by another department, locked in approved state, or belonging to another tenant.
  • Define atomic vs. partial batch semantics explicitly (reject the entire batch inside a transaction if any item is unauthorized, reporting which item failed without leaking data from unreadable IDs).
4. Eliminate TOCTOU Between Authorization Check and State Mutation

If you check if (quote.status === 'pending_approval') in memory and then run an unscoped UPDATE quotes SET status = 'approved' WHERE id = $1, a concurrent edit can modify quote.amount between the check and the write!

  • Bind the authorization preconditions into the atomic SQL UPDATE ... WHERE id = $1 AND tenant_id = $2 AND status = 'pending_approval' AND version = $3 (or lock the row with SELECT ... FOR UPDATE inside the transaction before evaluating the policy).

Enthaltene Dateien 1

  • SKILL.md