Cross-site scripting vzniká, když data určená k zobrazení získají v prohlížeči význam spustitelného kódu. Nebezpečná hodnota může přijít z formuláře, URL, databáze, externího API i kompromitované závislosti. Output encoding patří k nejsilnějším obranám, funguje však pouze pro přesný kontext, v němž browser data interpretuje. Escaping určený pro text mezi tagy nemusí ochránit script, style, URL ani event handler. Bezpečný návrh proto nezačíná seznamem payloadů, ale zachováním hranice mezi kódem aplikace a nedůvěryhodnými hodnotami.
Jedna stránka obsahuje několik jazyků
HTML dokument může současně nést markup, atributy, JavaScript, CSS a navigační URL. Hodnota bezpečná jako text může uvnitř script stringu ukončit literál. Hodnota uzavřená v atributu může stále vytvořit javascript: odkaz. Každý přechod do další gramatiky mění požadavky.
Framework auto-escaping obvykle dobře chrání běžný HTML text a quoted atributy. Záruka končí u raw renderingu, string concatenation, inline kódu, nebezpečných DOM API a některých third-party widgetů. Tato místa potřebují samostatný audit.
Escaping patří na poslední výstupní hranici
Ukládání HTML-encoded vstupu do databáze smíchá prezentaci s daty. Stejná hodnota pak může být použita v JSON, e-mailu nebo atributu, kde platí jiná pravidla. Často také vznikne double encoding, protože template správně escapuje již upravený string.
Databáze má uchovat sémantickou hodnotu, business vrstva ji validuje podle domény a renderer vybere encoder podle cílového kontextu. Raw output musí být viditelná a výjimečná operace.
Nejbezpečnější nebezpečný kontext je ten, který nevznikne
Vkládat nedůvěryhodnou hodnotu přímo do inline scriptu, style bloku, názvu atributu nebo event handleru je obtížné zabezpečit a snadné později rozbít. Data lze předat jako JSON response, bezpečně serializovaný script data blok nebo obyčejný atribut a načíst je strukturovaným API.
V DOM se pro text používá textContent, nikoli innerHTML. Elementy a atributy lze vytvářet pomocí DOM metod. Bezpečný design tak nedovolí browseru znovu parsovat arbitrary string jako code-capable markup.
Povolené rich text HTML potřebuje sanitizer
Komentář nebo editor může úmyslně podporovat odkazy, seznamy a zvýraznění. Escapovat celý obsah by odstranilo funkci, proto se použije udržovaný HTML sanitizer s allowlistem. Musí řešit nebezpečné atributy, URL schemes, SVG či MathML podle podpory a chybové zotavení parseru.
Sanitization se provádí na známé hranici a výsledek získá odlišný trusted HTML typ. Pozdější decode nebo nekontrolované spojení stringů může ochranu zrušit. Regex není vhodný parser tolerantního HTML.
URL potřebuje validaci významu i attribute encoding
Escapování uvozovek udrží hodnotu uvnitř href, ale neudělá cíl bezpečný. Aplikace musí URL parsovat a povolit očekávané scheme, hosty nebo interní cesty. Open redirect a nebezpečný scheme zůstávají problémem i při dokonale validní HTML syntaxi.
Nejprve se ověří navigační politika a normalizovaný význam, potom se při renderingu použije encoder atributu. Spojit oba kroky do jednoho string replacementu skrývá dvě rozdílné bezpečnostní odpovědnosti.
DOM-based XSS vzniká po bezpečném serverovém renderu
Server může odeslat korektní stránku a klientský kód později přečíst fragment URL, storage nebo message event a vložit hodnotu přes innerHTML. Frameworkové escaping z původního renderu tuto cestu nechrání. Je nutné inventarizovat sources a sinks v browser aplikaci.
Nebezpečné operace lze odstranit nebo uzavřít za malý počet reviewovaných helperů. Third-party komponenta, která očekává HTML string, potřebuje stejný trust model jako vlastní raw rendering.
CSP omezuje dopad, ale není náhradou
Content Security Policy může zakázat nečekané inline skripty a omezit zdroje kódu. Nonce nebo hash povolí známé skripty a reporting upozorní na porušení. Přísná politika často zastaví část exploitů, i když se markup podařilo vložit.
Legacy výjimky, nesprávně široké zdroje a některé DOM scénáře však ochranu oslabují. CSP je defense in depth vedle contextual encoding, sanitization a bezpečných API, nikoli důvod tolerovat injection.
Trusted Types mohou vynutit hranici v klientu
Ve velké aplikaci lze pomocí Trusted Types omezit code-capable DOM sinks tak, aby nepřijímaly obyčejné stringy. Hodnota musí vzniknout přes schválenou policy, která používá sanitizer nebo jiný kontrolovaný proces. Skryté předpoklady se tím mění na technicky vynutitelnou smlouvu.
Zavedení vyžaduje migraci a monitoring report-only režimu. Neřeší samo chybnou policy, ale výrazně zmenšuje počet míst, kde náhodná hodnota může skončit jako markup.
Test musí sledovat výsledné chování browseru
Sada obsahuje uvozovky, angle brackets, ampersandy, nebezpečné schemes, malformed markup a Unicode edge cases. Nestačí hledat substring v HTTP response. Test má ověřit DOM, vlastnost atributu a fakt, že se nespustil nečekaný kód. Klientské transformace patří do stejného scénáře.
Každý raw sink má mít zdokumentovaný důvod, původ dat a ochrannou vrstvu. XSS prevence je průběžná vlastnost rendering pipeline, kterou může změnit upgrade template enginu i nová frontend komponenta.
Bezpečnostní linting a code search mohou nové nebezpečné sinks zachytit ještě před review.
Bezpečná architektura udržuje data jako data
Contextual encoding funguje, protože zachovává rozdíl mezi hodnotou a programem. Sanitization je řízená výjimka pro omezený markup, CSP a Trusted Types přidávají další bariéry. Největší přínos přinášejí API, kde je bezpečná operace nejjednodušší a raw interpretace nápadná.
Jádrem ochrany není znalost jedné escape funkce. Je to přesné určení cílového kontextu, použití API navrženého pro tento kontext a odstranění míst, kde nedůvěryhodný text vůbec může získat spustitelný význam.