Prevence cross site scripting (XSS)
- Název pochází z raných verzí útoku, kdy se jednalo o krádež dat přes webové stránky
- Od té doby se rozšířil k injektování takřka jakéhokoli obsahu
- Útok je závažný, protože může vést k vydávání se za účet / uživatele, sledování uživatele, načítání externího obsahu nebo krádeži citlivých dat
- K zabránění XSS je zapotřebí využít správnou kombinaci technik
- Žádná technika sama o sobě XSS nevyřeší
Framework security
- V aplikacích vyvinutých pomocí moderních web frameworků se vyskytuje méně XSS chyb
- Frameworky vývojáře vedou ke správným postupům a pomáhají zmírnit XSS pomocí templatingu, escapování a dalších funkcí
- Vývojáři si přesto musí být vědomi problémů, které mohou nastat
- Únikové cesty, kterých frameworky používají k přímé manipulaci s DOM
- Reactí
dangerouslySetInnerHTMLbez sanitizace HTML - React neumí zpracovat
javascript:nebodata:URL bez specializované validace bypassSecurityTrustAs*funkce angularu- Template injection
- Neaktuální / staré pluginy a komponenty
- Zjistěte, jak váš framework brání XSS a kde má mezery
- V některých případech budete muset provést nějakou ochranu navíc
- V takovém případě je rozhodující encoding výstupu a HTML sanitizace
Obrana proti XSS
- Pro úspěšný útok je potřeba do stránky vložit a spustit škodlivý obsah
- Každá proměnná ve webové aplikaci musí být chráněna
- Dokonalá odolnost proti injektáži je zajištění validace a escapování pro každou proměnnou
- Každá proměnná, která tímto procesem neprojde, je potenciální slabinou
- Frameworky usnadňují zajištění validace a sanitizace proměnných
- Ani frameworky ale nejsou dokonalé
- V reactu a angularu stále existují bezpečnostní mezery
- Encoding výstupu a sanitizace HTML pomáhají nedostatky řešit
Encoding výstupu
- Pokud je potřeba data bezpečně zobrazit přesně tak, jak byla zadána
- Proměnné by neměly být interpretovány jako kód ale text
- Používejte výchozí ochranu encoding výstupu vašeho frameworku
- Automatický encoding a escapovací funkce jsou integrovány ve většině frameworků
- Použijte knihovnu pro encoding výstupu, pokud framework nepoužíváte nebo potřebujete pokrýt jeho mezery
- Existuje mnoho různých způsobů, protože se zpracovává HTML, JS, URL, CSS a další
- Použití nesprávné metody může přinést nedostatky nebo poškodit funkčnost aplikace
Encoding HTML
- Jde o vložení proměnné mezi dvě HTML značky (
<div>,<b>)
<div> $varUnsafe </div>
- Útočník může změnit data, která jsou v
$varUnsafeuložena - to vede k útoku na webovou stránku
<div> <script>alert`1`</script> </div> // Example Attack
- Použijte pro proměnnou HTML entity encoding, když ji přidáváte do webové šablony a chcete ji bezpečně přidat do HTML
- Podívejte se na atribut
.textContent, protože automaticky zakóduje HTML entitu, pokud používáte javascript pro zápis do HTML
& &
< <
> >
" "
' '
Encoding HTML atributů
- Odkazují na umístění proměnné v hodnotě atributu HTML
- Např. při změně odkazu, skrytí prvku, přidání
altnebo CSS stylů
<div attr="$varUnsafe">
<div attr=”*x” onblur=”alert(1)*”> // Example Attack
- Obklopte proměnné uvozovkami
"nebo'
- Uvozovky výrazně snižují množinu znaků, které je potřeba encodovat, což zvyšuje spolehlivost aplikace
- Podívejte se na metody
.setAttributea[attribute], které automaticky encodují HTML atribut, pokud používáte javascript
- Atributy, které akceptují javascript (
onClick), není bezpečné používat s nedůvěryhodnými hodnotami atributů
Encoding javascriptu
- Týká se umístění proměnných v inline javascriptu, který je vložen do HTML
- Jediné “bezpečné” místo pro umístění proměnných v JS je uvnitř “citované datové hodnoty”
- Vše ostatní je považováno za nebezpečné a proměnné by se tam neměly umisťovat
<script>alert('$varUnsafe’)</script>
<script>x=’$varUnsafe’</script>
<div onmouseover="'$varUnsafe'"</div>
- Encodujte všechny znaky pomocí
\xHH
- Encoding knihovny často obsahují funkci
EncodeForJavaScriptnebo podobnou, která výše zmíněné podporuje
- Ověřte, zda je hlavička
Content-Typeapplication/jsonv případě JSONu
Encoding CSS
- Vztahuje se k proměnným umístěných v inline CSS
- To je běžné například v případě přizpůsobení vzhledu stránek
- CSS jsou překvapivě mocné - bylo použito k mnoha typům útoků
- Proměnné by měly být umístěny pouze v hodnotě CSS property
- Vše ostatní je považováno za nebezpečné a proměnné by se tam neměly umisťovat
<style> selector { property : $varUnsafe; } </style>
<style> selector { property : "$varUnsafe"; } </style>
<span style="property : $varUnsafe">Oh no</span>
- Podívejte se na použití
style.property = xv případě, že používáte javascript- Automaticky se zde encoduje CSS
Encoding URL
- Vztahuje se k proměnným umístěným do URL adresy
- Nejčastěji vývojáři přidávají URL parametr, který se pak použije k nějaké operaci
<a href="http://www.owasp.org?test=$varUnsafe">link</a >
- Ujistěte se, že jsou všechny atributy plně uvozeny jako v JS nebo CSS
Časté chyby
- Proveďte encoding URL a pak kódování HTML atributů
url = "https://site.com?data=" + urlencode(parameter)
<a href='attributeEncode(url)'>link</a>
- Podívejte se na použití
window.encodeURIComponent(), pokud ke kostrukci URL používáte javascript, která automaticky encoduje vložená data
Nebezpečný kontext
- Kódování výstupu není dokonalé - ne vždy zabrání XSS
- Taková místa jsou známá jako nebezpečný kontext, do kterých patří
- Callback funkce
- Místa s URL zpracovávanými v kódu (
{ background-url: “javascript:alert(xss)”; }) - Javascript event handlery (
onclick,onerror) - Nezabezpečené JS funkce (
eval,setInterval)
- Neumisťujte proměnné do nebezpečných kontextů, protože ani encoding nemusí XSS zabránit
Sanitizace HTML
- Někdy potřebují mít uživatelé možnost vytvářet HTML
- Jedním ze scénářů je umožnit jim změnit styl nebo strukturu pomocí WYSIWYG editoru
- Encoding výstupu sice zabrání XSS, ale může narušit zamýšlenou funkčnost (styl nebude vykreslen)
- Použijte sanitizaci HTML v těchto případech
- Ta odstraní nebezpečné HTML z proměnné a vrátí bezpečný HTML řetězec
- Použijte například DOMPurify
let clean = DOMPurify.sanitize(dirty);
- Pokud obsah nejdříve sanitizujete a pak jej upravíte, můžete tím přijít o veškeré zabezpečení
- Zkontrolujte, zda sanitizovaný řetězec “nezmutoval” před tím, než jej použijete
- To je také považováno za nebezpečné
- Pravidelně upgradujte a záplatujte používané sanitizační knihovny
- Prohlížeče mění funkčnost a tím vznikají i nové způsoby, jak docílit XSS
Bezpečné sinks
- XSS sink je místo, kde je proměnná umístěna na stránce
- Mnoho sinks, kam lze proměnné umístit jsou však bezpečné
- Sinks považují proměnnou za text, takže ji nespustí
- Zrefaktorujte kód tak, abyste odstranili reference na nezabezpečené sinks (
innerHTML) a místo nich použijtetextContentnebovalue
elem.textContent = dangerVariable;
elem.insertAdjacentText(dangerVariable);
elem.className = dangerVariable;
elem.setAttribute(safeName, dangerVariable);
formfield.value = dangerVariable;
document.createTextNode(dangerVariable);
document.createElement(dangerVariable);
elem.innerHTML = DOMPurify.sanitize(dangerVar);
- Bezpečné HTML atributy:
align,alink,alt,bgcolor,border,cellpadding,cellspacing,class,color,cols,colspan,coords,dir,face,height,hspace,ismap,lang,marginheight,marginwidth,multiple,nohref,noresize,noshade,nowrap,ref,rel,rev,rows,rowspan,scrolling,shape,span,summary,tabindex,title,usemap,valign,value,vlink,vspace,width
Další možnosti obrany
- Framework, encoding výstupu a HTML sanitizace poskytnou nejlepší ochranu
- Jsou doporučeny za všech okolností
- Zvažte použití následujících prvků ke zvýšení bezpečnosti
- Cookie atributy
- Mění způsob interakce javscriptu a prohlížečů s cookies
- Cookie atributy se snaží snížit dopad XSS, ale nezabraňují spouštění škodlivého kódu, ani neřeší hlavní příčinu zranitelnosti
- Content Security Policy
- Allow list, který zabraňuje načítání obsahu, například z jiných URL
- Použijte CSP jako další vrstvu obrany, postupujte podle OWASP cheat sheetu
- Web Application Firewall
- Vyhledává známé útočné řetězce a blokuje je
- Jsou nespolehlivé a pravidelně se objevují techniky, jak je obejít
- WAF také neřeší hlavní příčinu XSS
- Nedoporučují se pro prevenci XSS, zejména XSS založenému na DOM
- Cookie atributy
Shrnutí pravidel prevence XSS
| Datový typ | Kontext | Code sample | Obrana |
|---|---|---|---|
| String | HTML body | UNTRUSTED DATA | HTML entity encoding |
| String | Bezpečné HTML atributy | <input type="text" name="fname" value="UNTRUSTED DATA "> | 1. HTML entity encoding 2. Umístěte nedůvěryhodná data do bezpečných atributů 3. Validujte nezabezpečené atributy (background, id, name) |
| String | GET parametr | <a href="/site/search?value=UNTRUSTED DATA ">clickme</a> | URL encoding |
| String | Nedůvěryhodná URL v href nebo src | <a href="UNTRUSTED URL ">clickme</a> <iframe src="UNTRUSTED URL " /> | 1. Kanonizujte vstup 2. Validujte URL adresu 3. Zaveďte seznam povolených adres a kontrolujte adresy oproti němu 4. Vyhněte se otevírání nového okna prohlížeče |
| String | CSS hodnota | HTML <div style="width: UNTRUSTED DATA ;">Selection</div> | 1. Validujte strukturu 2. Hexadecimálně encodujte 3. Pečlivě navrhněte CSS funkcionalitu |
| String | Javascript proměnná | <script>var currentValue='UNTRUSTED DATA ';</script> <script>someFunction('UNTRUSTED DATA ');</script> | 1. Zajistěte, aby byly proměnné uvozeny a hexadecimálně encodovány 2. Vyvarujte se encodingu se zpětným lomítkem |
| String | HTML body | <div>UNTRUSTED HTML</div> | Validujte HTML (JSoup, AntiSamy) |
| String | DOM XSS | <script>document.write("UNTRUSTED INPUT: " + document.location.hash );<script/> | https://cheatsheetseries.owasp.org/cheatsheets/DOM_based_XSS_Prevention_Cheat_Sheet.html |
Shrnutí pravidel pro encoding výstupu
- Účelem je převést nedůvěryhodný vstup do bezpečné formy, aniž by se spouštěl v prohlížeči
| Encoding typ | Encoding mechanismus |
|---|---|
| HTML entity encoding | Převádí & na &, < na <, > na >, atd. |
| Encoding HTML atributu | Encoduje všechny znaky pomocí &#HH; (hexadecimálně), kromě alfanumerických znaků |
| URL encoding | Standardní kódování pomocí procent, viz https://www.w3schools.com/tags/ref_urlencode.asp |
| Javascript encoding | Encoduje všechny znaky pomocí \uXXXX unicode kódování (X = integer), kromě alfanumerických znaků |
| CSS Hex encoding | Podporuje \XX a \XXXXXX |