Zabezpečení webových aplikací: příčiny selhání a best practices ochrany

Proč zabezpečení webu selhává a jak tomu předejít

Webové aplikace jsou složité systémy, které zpracovávají neustálý tok neověřených vstupů: parametry URL, těla požadavků, cookies, hlavičky a události v prohlížeči. Tři z historicky nejkritičtějších tříd zranitelností jsou XSS (Cross-Site Scripting), CSRF (Cross-Site Request Forgery) a SQL Injection. Tyto chyby vyplývají z chybné práce s důvěrou: důvěra v data od uživatele, v prohlížeč, v databázi a v síť. Tento článek shrnuje hrozby, kořenové příčiny a praktické, rámcově nezávislé postupy obrany.

Model hrozeb a kořenové příčiny

  • Nedostatečná validace a kontextové kódování: vstupy se bez úprav míchají s kódem (HTML, JS, SQL).
  • Zneužitelný stav relace: absence ochrany proti podvržení nebo odcizení session (CSRF tokeny, SameSite, rotace identifikátorů).
  • Chybná separace kompetencí: aplikace vykonává příkazy v databázi s nadměrnými oprávněními, klientský kód důvěřuje nedůvěryhodným datům.
  • Slabá pozorovatelnost: chybí detekce anomálií, korelace logů a alerting pro podezřelé sekvence požadavků.

Cross-Site Scripting (XSS): typy a scénáře

  • Reflected XSS: škodlivý vstup je vrácen v odpovědi (např. parametr q ve vyhledávání), vykoná se v prohlížeči oběti.
  • Stored XSS: payload uložený v databázi (komentáře, profily) a vykonávající se při každém zobrazení.
  • DOM-based XSS: manipulace s DOM na klientovi (např. location.hash, document.write) bez serverového podílu.

XSS: dopady a útokové vektory

Útočník může číst a zapisovat data v kontextu domény oběti, krást cookies (pokud nejsou HttpOnly), provádět akce jménem uživatele, upravovat obsah stránky nebo injektovat phishingové útoky. Významná rizika nastávají u SPA aplikací s bohatým JavaScriptem, kde manipulace s DOM probíhají častěji a v širším rozsahu.

Obrana proti XSS: vícevrstvá strategie

  • Kontextové kódování (escaping): při výstupu do HTML textu kódujte &<>"'; v HTML atributech navíc kontrolujte uzávorky a nebezpečné protokoly; v JavaScriptových řetězcích escapujte speciální znaky; v URL parametrech používejte percent-encoding.
  • Šablonovací systémy s automatickým escape: preferujte enginy a frameworky, které mají auto-escaping (např. výchozí šablonovače na straně serveru, React/Angular na klientu). Při vědomé potřebě „raw“ výstupu proveďte bezpečné filtrování pomocí whitelistu.
  • Content Security Policy (CSP): nasazujte pravidla bez unsafe-inline; preferujte přístup založený na nonce (script-src 'nonce-…') a oddělení skriptů do externích souborů. U větších SPA zvažte použití Trusted Types pro vynucení bezpečných API při přiřazování do DOM.
  • HttpOnly a Secure pro cookies: zamezí čtení session skripty; kombinujte s SameSite pro mitigaci CSRF.
  • Sanitizace HTML: pokud je nutné zobrazovat uživatelský HTML obsah, používejte knihovny s whitelistem značek a atributů a bez event handlerů či nebezpečných URL schémat.
  • Zakázané konstrukce: omezte používání eval, new Function, document.write a dynamických přiřazení do innerHTML; preferujte bezpečná API (textContent, setAttribute s validací).

CSRF (Cross-Site Request Forgery): princip a symptomy

CSRF zneužívá skutečnost, že prohlížeč automaticky přikládá cookies k požadavkům na danou doménu. Útočník podstrčí oběti požadavek (formulář, obrázek, skript, CORS), aby aplikace vykonala akci, kterou oběť nechtěla (změna e-mailu, hesla, převod peněz). CSRF cílí na stavy – operace měnící stav (POST/PUT/PATCH/DELETE) bez dostatečné verifikace uživatelova záměru.

CSRF: obranné techniky

  • Antiforgery tokeny: kryptograficky náhodné, vázané na relaci, jednorázové nebo rotované; validujte je u každého měnícího požadavku.
  • SameSite atribut u cookies: SameSite=Lax je rozumný výchozí stav; pro citlivé akce a tradiční weby lze použít Strict (pozor na uživatelskou zkušenost); kombinujte s Secure a HttpOnly.
  • Validace původu: kontrola hlaviček Origin a Referer u state-changing požadavků; odmítnout prázdné nebo cizí originy.
  • Oddělení idempotentních a měnících operací: GET musí být bez vedlejších efektů; změny vyžadují POST s tokenem a případně opětovnou autentizaci.
  • Vyvarovat se „cookie-only“ autentizace pro API: preferujte bearer tokeny v Authorization hlavičce pro veřejná API (tyto tokeny se nepřikládají automaticky napříč originy).
  • Nespoléhat na CORS: CORS řeší sdílení zdrojů mezi originy, nikoli CSRF – nechrání před automatickým přikládáním cookies u jednoduchých požadavků.

SQL Injection: kořenový problém a varianty

  • Klasická (error/union-based): manipulace dotazu přímou injekcí vkládaných řetězců.
  • Blind (boolean/time-based): inference na základě odezvy, i když se chyby nesdělují.
  • Second-order: škodlivý vstup uložený a později znovu použitý v jiném dotazu.

SQL Injection: obranné patterny

  • Parametrizované dotazy: používejte prepared statements s bind parametry; nikdy neskládejte SQL řetězce pomocí konkatenace uživatelských vstupů.
  • ORM/Query builder: využívejte bezpečná API, vyhýbejte se „raw SQL“ bez správné parametrizace.
  • Princip nejmenších oprávnění: aplikační databázový účet má minimální práva (bez DROP či ALTER, pouze nezbytná SELECT, INSERT, UPDATE, DELETE).
  • Whitelisting vstupů: číselné identifikátory převádějte na integer, enumerace validujte proti seznamu; textové vstupy nikdy nepoužívejte přímo ve struktuře dotazu (např. názvy sloupců).
  • Oddělení povinností: různé funkční oblasti a batch úlohy používejte samostatné databázové účty.
  • Bezpečné logování: logy nesmí obsahovat celé dotazy s citlivými daty; maskujte hodnoty a dbejte na dodržování GDPR.

Bezpečné zpracování vstupů: od validace k normalizaci

  • Kanonizace: před validací převádějte vstupy do kanonického tvaru (normalizace Unicode, odstranění nulových bytů, sjednocení konců řádků).
  • Validace před byznysem: odmítněte nevalidní vstupy co nejdříve, vracejte přesné, ale bezpečné chyby (bez úniku informací o struktuře systému).
  • Separace dat a kódu: vstupní data nikdy nesmějí měnit programovou logiku nebo instrukční kontext.

Bezpečná relace a správa cookies

  • Rotace session ID: po přihlášení i při zvyšování oprávnění.
  • Časová omezení: idle timeout a absolute timeout, opětovná autentizace u kritických akcí.
  • Flagy: HttpOnly, Secure, SameSite; zákaz ukládání session do URL.

Bezpečnostní hlavičky a konfigurace serveru

  • CSP (viz výše), X-Content-Type-Options: nosniff, Referrer-Policy, Permissions-Policy, Strict-Transport-Security pro vynucení HTTPS.
  • Oddělení statiky a aplikace: reverzní proxy, omezení expozice admin rozhraní, rate-limiting a ochrana proti brute-force útokům.

Testování: SAST, DAST, IAST a fuzzing

  • SAST: statická analýza kódu v CI systému, pravidla pro nebezpečná API a šablonové konstrukce.
  • DAST: dynamické skenery proti běžící aplikaci, integrované do QA pipeline s autentizací.
  • IAST/RASP: senzory v aplikaci pro přesnější detekci skutečných problémů během testování.
  • Fuzzing: generování nečekaných vstupů a sekvencí požadavků s monitoringem chyb a anomálií.

Bezpečný SDLC a governance

  • Bezpečnostní požadavky: definujte nefunkční požadavky (CSP, tokeny, parametrizace) již při návrhu.
  • Code review s bezpečnostními checklisty: povinné schvalování změn s důrazem na kontext výstupu, práci s databází a relací.
  • Závislosti: skenování knihoven (SCA), politiky verzí, SBOM a rychlá reakce na CVE.
  • Incident response: runbooky, detekce XSS/SQLi anomálií, blokace a hotfix postupy, post-mortem a lessons learned.

Monitoring a detekce útoků

  • Aplikační logy: korelace neobvyklých parametrů, chybových kódů, dlouhých dotazů a časování.
  • WAF/Runtime ochrany: signatury pro typické payloady (např. <script>, UNION SELECT), ale vždy jako doplněk k opravdovým nápravám v kódu.
  • Telemetrie DB: výstrahy na sleep() a časové anomálie, nezvyklé množství chybových dotazů, eskalace práv.

Specifika SPA, API a mikrofrontendů

  • SPA: důsledné používání bezpečných bindingů, CSP s nonce, Trusted Types; správa stavu bez serializace nedůvěryhodných dat do innerHTML.
  • API: oddělené domény, autentizace v hlavičkách (bearer tokeny), CORS s explicitními allowlisty; žádné reflektování vstupů do chybových zpráv bez kódování.
  • Mikrofrontendy: sandboxované <iframe> s atributy sandbox a allow; přísná CSP a postMessage s validací originu.

Praktické anti-patterny a jak je odstranit

  • Skládání HTML/JS řetězců: nahraďte komponentovým či šablonovým enginem s auto-escapingem.
  • „Globalní“ databázový uživatel: vytvořte role s minimálními právy pro jednotlivé služby.
  • CSRF ochrana jen na některých formulářích: tokenizujte všechny měnící akce, včetně AJAX požadavků.
  • Logování celých SQL dotazů a cookies: maskujte a anonymizujte, dodržujte zásady ochrany soukromí.

Checklist: XSS, CSRF, SQLi v praxi

  • XSS: auto-escaping, CSP bez unsafe-inline, Trusted Types (pokud možné), zákaz eval, HttpOnly cookies.
  • CSRF: antiforgery token, SameSite a Secure cookies, kontrola Origin a Referer, změny pouze přes POST.
  • SQLi: parametrizované dotazy, whitelist typů, omezená databázová práva, žádné skládání SQL řetězců.
  • Testování: SAST/DAST v CI, skenování závislostí, pravidelné penetrační testy a threat modeling.

Závěr: bezpečnost jako inženýrská disciplína

Ochrana proti XSS, CSRF a SQL Injection není jednorázový úkol, ale kontinuální proces, který začíná návrhem, pokračuje implementací bezpečných konstrukcí, průběžným testováním a končí provozní observabilitou a připraveností na incidenty. Úspěch spočívá v přísném oddělení dat od kódu, v kontextově správném kódování, v kryptograficky silné obraně proti podvržení požadavků a v disciplinovaném přístupu k databázím. Investice do bezpečného SDLC snižuje rizika, zlepšuje důvěru uživatelů a dlouhodobě zkracuje dobu potřebnou k dodání změn.