Bezpečnost GraphQL

Bezpečnost GraphQL

Proč jsou GraphQL API bezpečnostně specifická

GraphQL přináší flexibilní dotazovací jazyk, kde si klient sám určuje tvar dat. To zásadně mění bezpečnostní model oproti RESTu: granularita (autorizace až na úroveň polí), kompozice (fragmenty, aliasy, unie), resource amplifikace (hloubka/šířka dotazů) a transport (často dlouhožijící spojení pro subscribce). Cílem tohoto článku je shrnout osvědčené postupy, jak navrhnout, implementovat a provozovat GraphQL API s robustními kontrolami proti zneužití a únikům dat.

Model hrozeb a bezpečnostní cíle

  • Důvěrnost: Zabránit exfiltraci dat skrze volitelnou strukturu dotazů a introspekci.
  • Integrita: Zajistit, že mutace respektují obchodní pravidla, transakční hranice a jemnozrnná oprávnění.
  • Dostupnost: Omezit DoS přes drahé dotazy, n+1 patrón, masivní aliasování a subscription fan-out.
  • Odpovědnost: Transparentní audit, korelace dotazů s identitou uživatele a operationName.

Autentizace a transportní vrstvy

  • TLS všude: Vynucujte HTTPS i pro WebSocket (wss://). Zabraňte downgrade a slabým šifrám.
  • OAuth 2.0 / OIDC: Přenášejte identity jako Bearer tokeny (JWT/PASETO) v hlavičce Authorization; nepřenášejte session v URL.
  • Krátká životnost a rotace: Access tokeny krátké, refresh tok řízen politikami (revoke, jti blacklisty).
  • mTLS / NULA: Pro B2B integrace zvažte vzájemné TLS a vazbu tokenu na kanál (DPoP/mtls-bound tokens).

Autorizace: od schématu po resolver

Autorizaci navrhujte deklarativně a konzistentně, ideálně přímo ve vrstvě schématu.

  • Model oprávnění: RBAC (role-based), ABAC (atributové), případně hybrid (role + podmínky nad kontextem a daty).
  • Per-field enforcement: Oprávnění vynucujte u každého pole (resolveru), nejen u kořenových typů Query/Mutation.
  • Directive-based guardy: Vlastní direktivy (např. @auth(role: "admin")) nebo knihovny typu GraphQL Shield/Envelop s pravidly na schéma.
  • Row- a column-level security: Omezte přístup k záznamům (RLS v DB) a k citlivým sloupcům; autorizace není jen v aplikaci.
  • Odlíšení chyb: Neposkytujte rozdílné chybové zprávy, které by prozrazovaly existenci/neexistenci objektů bez oprávnění.

Introspekce a schéma: co (ne)prozrazovat

  • Řízená introspekce: V produkci zvažte vypnutí introspekce anonymním uživatelům nebo její povolení pouze privilegovaným rolím / na neveřejných endpointech (např. build-time SDL dump pro nástroje místo runtime introspekce).
  • Operation whitelisting: Persistované dotazy (APQ/whitelist) – klient posílá pouze hash dotazu; server odmítne „neznámé“ operace.
  • Verzování schématu: Stabilní kontrakty, deprecation anotace a telemetry pro bezpečné odstraňování nechtěných polí.

Omezení složitosti dotazů (DoS prevence)

  • Depth limit: Maximální hloubka AST (např. 8–12) s výjimkami pro bezpečné typy.
  • Complexity scoring: Váhy polí (např. cost: O(1), O(n), O(n log n)) a per-request budget; odmítnout dotaz nad limitem.
  • Aliases & batching guard: Limit počtu aliasů a opakování stejného pole; detekce „amplifikačních“ vzorů.
  • Timeouty a maxTokens: Časové limity resolverů a limity velikosti payloadu/AST; circuit breakers na úrovni gateway.
  • Rate limiting/throttling: Per IP/klient/uživatel; kombinovat s token bucket/Leaky Bucket na reverse proxy.

Validace vstupů a typová bezpečnost

  • Custom scalars: Email, URL, UUID, SafeInt, NonEmptyString s validační logikou (runtime i schema-first).
  • Whitelisting hodnot: Enumy místo volných stringů; normalizace Unicode, zákaz neviditelných znaků a NUL.
  • Neprolévat „raw“: Nikdy neskládejte SQL/NoSQL dotazy z uživatelských stringů. Používejte parametrizaci a query buildery.
  • Velikost vstupů: Omezte velikost proměnných, počty prvků v listu a hloubku vnoření Input typů.

Chyby, logování a úniky informací

  • Maskování chyb: Do errors[].message posílejte neutrální zprávy; interní stacktrace pouze do serverových logů.
  • Obohacení o kód chyby: V rozšíření (extensions.code) vracejte strojově čitelný kód (např. FORBIDDEN, BAD_USER_INPUT).
  • PII hygiene: Nelogujte plné dotazy s citlivými proměnnými; maskujte hodnoty (např. hesla, tokeny, čísla karet).
  • Traceability: Vyžadujte operationName, korelační ID a logujte metriky (délka, hloubka, complex score, počet resolver calls).

N+1 problém, cache a resource amplifikace

  • Dataloader pattern: Batchujte přístupy do datových zdrojů (per request context) a předcházejte exponenciálnímu růstu dotazů.
  • Cache vrstvy: Per-request cache (resolver-level), aplikační cache (TTL), a bezpečná CDN cache pouze pro public data. U privátních odpovědí nikdy necacheujte bez kontextu identity.
  • Limitované zobrazení: Page-size limity, kursory (Relay) a server-side hard caps i při volbě klienta.

CORS, CSRF a bezpečnost prohlížeče

  • CORS allowlist: Explicitní allowed origins; nikdy nepovolujte * s credentials.
  • CSRF rizika: GraphQL přes cookie-based session vyžaduje anti-CSRF tokeny u mutací; u bearer tokenů v hlavičce je riziko menší, ale validujte Origin/Referer.
  • Security headers: Content-Security-Policy, Referrer-Policy, X-Content-Type-Options a Strict-Transport-Security pro konzolové UI (GraphiQL/Apollo Sandbox).

Uploads, soubory a binární data

  • Multipart handling: Omezte počet souborů, velikost a typ MIME; skenujte malware; ukládejte mimo aplikační server.
  • Dočasné URL: Generujte krátkodobé podpisy (pre-signed URL) a nekonzumujte velké streamy přes GraphQL resolver.

Subscriptions a WebSocket bezpečnost

  • Handshake autentizace: Ověřujte token při connection_init; pravidelně reautentizujte u dlouhých spojení.
  • Per-event autorizace: Kontrolujte práva při každém publishi (ne jen při subscribe). Zabraňte topic wildcard únikům.
  • Backpressure & limit: Omezte počet simultánních subscription na uživatele/klienta a velikost fronty zpráv.

Federace, gateway a hranice důvěry

  • Apollo Federation / Schema stitching: Gateway je povrch útoku – aplikujte tytéž limity hloubky/komplexity už na hraně.
  • Trust mezi subgrafy: Předávané @requires/@key informace mohou prozradit interní identifikátory; minimalizujte citlivá pole v subgrafech.
  • Authz na hraně: Vynucujte základní politiku v gateway (např. denylist), detailní oprávnění v doménových službách.

Bezpečný vývoj a testování (SDLC)

  • Schema linting: Zakazujte „leaky“ typy, nepoužité kořeny, příliš generické scalary; vyžadujte @deprecated s důvodem.
  • SAST/DAST pro GraphQL: Používejte skenery schématu a dynamické testy (fuzzing proměnných, mutací, fragmentů).
  • Contract testing: Persistované dotazy jako kontrakty – CI odmítne breaking changes bez migračního plánu.
  • Chaos a zátěž: Testujte limity hloubky, aliasů, rate-limit chování a resilience resolverů na časové limity.

Provoz, observabilita a reakce na incidenty

  • Metriky: p50/p95/p99 latence na operaci, počet resolverů na dotaz, hloubka/complex score, chybovost podle kódu.
  • Rozšířený audit: Logujte operationName, identitu, schéma verzi a cost; pro citlivé akce i před/po stav.
  • WAF/GraphQL firewally: Schémově uvědomělé filtry (poznají AST) jsou účinnější než klasické signatury.
  • Runbooky: Rychlé nasazení denylistu/přísnějších limitů, vypnutí introspekce, odpojení určitých klientů, rotace klíčů.

Časté anti-patterny

  • „Všechno přes jeden admin token“: Nedělejte ze serveru superuživatele vůči DB; používejte role a RLS.
  • Veřejná introspekce v produkci: Zbytečně prozrazuje interní model a názvosloví.
  • Bez limitů hloubky/komplexity: Vystavujete se levnému DoS.
  • Chyby s interními detaily: Stacktrace a SQL chybové kódy ve veřejné odpovědi.
  • Cache privátní odpovědi v CDN: Únik dat mezi tenantry.

Příklad politiky složitosti (ilustrace)

{ getUser(id: ID!): User @cost(value: 5) } type User { id: ID! @cost(value: 1) name: String! @cost(value: 1) posts(limit: Int): [Post]! @cost(value: 2, multipliers: ["limit"]) } type Post { id: ID! @cost(value: 1) title: String! @cost(value: 1) comments(limit: Int): [Comment]! @cost(value: 3, multipliers: ["limit"]) } 

Server při validaci spočítá cost na základě AST a odmítne dotazy přesahující per-tenant budget.

Bezpečnostní checklist pro GraphQL

  • Transport & AuthN: HTTPS/WSS, krátké tokeny, žádné tokeny v URL, reautentizace WS.
  • AuthZ: Field-level guardy (directive/middleware), RLS, nediskriminační chybové zprávy.
  • Introspekce: Vypnout nebo omezit, preferovat persistované dotazy.
  • Limity: Depth/complexity, alias count, timeouty, payload size, rate limiting.
  • Validace: Custom scalars, enumy, limit velikostí, parametrizované dotazy do DB.
  • Chyby & logy: Maskovat, kódy v extensions, PII hygiene, korelace.
  • Performance: Dataloader, stránkování s caps, cache s ohledem na identitu.
  • Subscriptions: Auth handshake, per-event authz, limity spojení/front.
  • Federace: Limity a authz v gateway, minimální důvěra mezi subgrafy.
  • Provoz: AST-aware WAF, metriky, runbooky pro incidenty.

Závěr

GraphQL zvyšuje agilitu, ale také nároky na disciplinovanou bezpečnost. Úspěch stojí na field-level autorizaci, řízené introspekci a důsledných omezeních složitosti dotazů. V kombinaci s bezpečným SDLC, observabilitou a runbooky pro incidenty lze dosáhnout API, které je zároveň flexibilní pro vývojáře a odolné vůči moderním útokům.

Pridaj komentár

Vaša e-mailová adresa nebude zverejnená. Vyžadované polia sú označené *