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í
dangerouslySetInnerHTML
bez 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
$varUnsafe
ulož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í
alt
nebo 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
.setAttribute
a[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
EncodeForJavaScript
nebo podobnou, která výše zmíněné podporuje
- Ověřte, zda je hlavička
Content-Type
application/json
v 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 = x
v 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žijtetextContent
nebovalue
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 |