Bezpečnost GraphQL API: Ochrana před útoky DoS a výpadky služby

Specifiká bezpečnosti GraphQL API

GraphQL představuje moderní a flexibilní dotazovací jazyk, který umožňuje klientům přesně definovat strukturu požadovaných dat. Tento přístup výrazně mění tradiční bezpečnostní model oproti REST API. Specifické bezpečnostní aspekty zahrnují granularitu autorizace až na úroveň jednotlivých polí, kompozici dotazů (fragmenty, aliasy, unie), amplifikaci zdrojů (hloubka a šířka dotazů) a specifika transportní vrstvy (například dlouhodobé WebSocket spojení pro subscriptions). Článek se zaměřuje na osvědčené metody návrhu, implementace a provozu bezpečných GraphQL API, které minimalizují riziko zneužití a úniku dat.

Model hrozeb a bezpečnostní cíle

  • Důvěrnost dat: Prevence neoprávněného přístupu a exfiltrace dat prostřednictvím variabilní struktury dotazů a introspekce schématu.
  • Integrita operací: Monitorování a zajištění, že mutace dodržují obchodní pravidla, transakční integritu a jemnozrnná oprávnění.
  • Dostupnost služby: Prevence DoS útoků prostřednictvím kontrol náročných dotazů, n+1 vzorů, nadměrného aliasování a explosionu subscription fan-outů.
  • Odpovědnost a auditovatelnost: Transparentní zaznamenávání dotazů s propojením na identitu uživatele a operationName, usnadňující forenzní analýzy.

Autentizace a zabezpečení transportní vrstvy

  • End-to-end TLS: Vynucení HTTPS i pro WebSocket (wss://), zabránění downgrade útokům a použití slabých šifrovacích algoritmů.
  • Standardy OAuth 2.0 a OIDC: Přenos identit pomocí Bearer tokenů (JWT, PASETO) v hlavičce Authorization, nikdy ne v URL parametrech.
  • Krátká životnost a rotace tokenů: Používání krátkodobých access tokenů, kontrolované refresh tokeny s revoke mechanismem a blacklistem.
  • Vzájemné TLS a vázání tokenů: Pro B2B scénáře doporučeno zvažovat mutual TLS a tokeny vázané na konkrétní kanál (DPoP, mtls-bound tokens).

Autorizace: od schématu až po resolver

Autorizace by měla být navržena deklarativně a konzistentně napříč celým API, ideálně přímo ve vrstvách schématu.

  • Modely oprávnění: Role-based (RBAC), atributové (ABAC) či kombinace obou, s možností vyhodnocovat podmínky nad kontextem a daty.
  • Per-field enforcement: Oprávnění aplikujte nejen na root typy Query a Mutation, ale i na jednotlivá pole (resolvery).
  • Directive-based ochrana: Používejte vlastní direktivy (například @auth(role: "admin")) nebo knihovny jako GraphQL Shield či Envelop.
  • Řízení přístupu na úrovni řádků a sloupců: Implementujte RLS (Row-Level Security) na databázové vrstvě a omezujte přístup k citlivým sloupcům.
  • Ochrana před odhalením existence dat: Nezobrazujte rozdílné chybové zprávy, které by mohly naznačovat přítomnost či absenci zdrojů bez oprávnění.

Introspekce a správa schématu

  • Řízená introspekce: V produkčním prostředí omezte introspekci pro anonymní uživatele nebo povolte pouze vybraným rolím, případně používejte statické SDL dumpy namísto runtime introspekce.
  • Persistované dotazy (operation whitelisting): Používejte mechanismy, kdy klient posílá pouze hash dotazu, což výrazně omezuje neznámé nebo škodlivé operace.
  • Správa verzí schématu: Řiďte stabilitu API pomocí anotací deprecation a monitorujte telemetrii pro bezpečné odstraňování zastaralých polí.

Omezení složitosti dotazů jako prevence DoS

  • Limit hloubky dotazu (depth limit): Nastavte maximální povolenou hloubku AST (například 8–12) s výjimkami pro důvěryhodné typy.
  • Skórování složitosti (complexity scoring): Aplikujte váhy na pole podle jejich náročnosti (např. O(1), O(n), O(n log n)) a stanovte per-request rozpočet, přesahující dotazy automaticky odmítejte.
  • Ochrana proti nadměrnému aliasování a batchingu: Omezujte počet aliasů a opakování polí, detekujte vzory amplifikace dotazů.
  • Timeouty a omezení tokenů: Zavádějte časové limity pro resolvery, limitujte velikost payloadu a AST, nasazujte circuit breakers na úrovni gateway.
  • Rate limiting a throttling: Implementujte omezení počtu požadavků na IP, uživatele či klienta za určitý čas, využívejte token bucket nebo Leaky Bucket algoritmy na reverzní proxy.

Validace vstupních dat a typová bezpečnost

  • Vlastní skalární typy: Definujte a validujte typy jako Email, URL, UUID, SafeInt, NonEmptyString na úrovni schématu i během běhu.
  • Whitelisting hodnot: Preferujte enumy před volnými řetězci, normalizujte Unicode, blokujte neviditelné znaky a nulové byty.
  • Zabránění SQL/NoSQL injection: Nikdy neskládejte dotazy zahrnující uživatelská data přímo – používejte parametrizované dotazy a query buildery.
  • Omezení velikosti vstupů: Kontrolujte velikost proměnných, počet prvků v polích a hloubku vnoření Input typů.

Zpracování chyb, logování a ochrana informací

  • Maskování chyb: Zobrazujte pouze neutrální a bezpečné chybové zprávy v odpovědích, interní detaily a stacktrace ukládejte výhradně do serverových logů.
  • Standardizované kódy chyb: Používejte strojově čitelné kódy chyb v extensions.code (např. FORBIDDEN, BAD_USER_INPUT).
  • Zachování soukromí (PII hygiene): Neukládejte a nelogujte kompletní dotazy s citlivými proměnnými, maskujte hesla, tokeny či čísla platebních karet.
  • Traceabilita: Požadujte přítomnost operationName a korelační ID, zaznamenávejte metriky jako délka dotazu, hloubka, skóre složitosti či počet volání resolverů.

Řešení problému n+1, caching a řízení resource amplifikace

  • Vzor Dataloader: Batchujte požadavky do datových zdrojů v kontextu jednotlivých požadavků, eliminujte nadměrné dotazy např. n+1 problém.
  • Cache na více úrovních: Používejte per-request cache na úrovni resolverů, aplikační cache s TTL a bezpečnou CDN cache pouze pro veřejná data; privátní odpovědi cacheujte pouze s ohledem na identitu uživatele.
  • Omezení velikosti výsledků: Aplikujte paginaci (page size limity, cursor-based paginaci jako Relay) a serverové hard caps i v případě, že klient požaduje větší objem dat.

Bezpečnostní opatření v prohlížeči: CORS a CSRF

  • Seznam povolených CORS originů: Explicitně definujte allowed origins, nikdy nepovolujte * v kombinaci s credentials.
  • Prevence CSRF: U cookie-based session autentizace vyžadujte anti-CSRF tokeny pro mutace; u bearer tokenů v hlavičce je riziko nižší, přesto validujte hlavičky Origin a Referer.
  • Bezpečnostní hlavičky: Nasazujte Content-Security-Policy, Referrer-Policy, X-Content-Type-Options a Strict-Transport-Security zejména pro konzolová UI jako GraphiQL či Apollo Sandbox.

Zpracování nahrávek, souborů a binárních dat

  • Omezení multipart požadavků: Regulujte počet souborů, jejich velikost a MIME typy, provádějte antivirové skenování a ukládejte soubory mimo aplikační servery.
  • Bezpečné dočasné URL: Generujte krátkodobé podepsané URL (pre-signed URL) pro přímý přístup k souborům, minimalizujte streamování velkých souborů přes GraphQL resolvery.

Bezpečnost subscriptions a WebSocket spojení

  • Autentizace při handshake: Ověřujte tokeny při connection_init eventu, pravidelně reautentizujte u dlouhodobých spojení.
  • Autorizace na úrovni událostí: Provádějte kontrolu oprávnění při každém publikování zprávy, ne pouze při přihlášení; zabraňte únikům dat přes topic wildcard.
  • Omezování zátěže: Limitujte počet současných subscription na uživatele či klienta a nastavte limity velikosti front zpráv, abyste zabránili přetížení.

Federace, gateway a správa důvěry

  • Apollo Federation a schema stitching: Brána (gateway) představuje primární vstupní bod útoků – aplikujte ji limit hloubky a komplexity, validaci i autorizaci.
  • Důvěra mezi subgrafech: Minimalizujte přenos interních identifikátorů v @requires/@key direkivách, aby nedocházelo k nechtěnému úniku dat.
  • Zabezpečení komunikace: Šifrujte komunikaci mezi jednotlivými subgrafech pomocí TLS a využívejte ověřování služeb (mutual TLS nebo podpisy), abyste zabránili neoprávněnému přístupu.
  • Monitoring a alerting: Sledujte metriky a anomálie napříč gateway a subgrafech, automaticky detekujte neobvyklé chování nebo zvýšené latence.
  • Verzování schémat: Spravujte změny na úrovni federace s jasným verzováním a plánem nasazení, aby nedocházelo k nekompatibilitám a bezpečnostním děrám.

Komplexita zabezpečení GraphQL API vyžaduje pečlivý přístup na mnoha úrovních – od vstupní validace přes řízení zátěže až po správu distribuované federace. Implementací navržených opatření lze výrazně snížit riziko DoS útoků a minimalizovat potenciál výpadků služby.

Nezapomínejte také na pravidelné testování bezpečnosti, revize schémat a aktualizaci závislostí, protože bezpečnost je kontinuální proces, který se přizpůsobuje novým hrozbám a technologiím.