Přeskočit na hlavní obsah

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: nebo data: URL bez specializované validace
    • bypassSecurityTrustAs* funkce angularu
    • Template injection
    • Neaktuální / staré pluginy a komponenty
  1. 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
  1. Používejte výchozí ochranu encoding výstupu vašeho frameworku
    • Automatický encoding a escapovací funkce jsou integrovány ve většině frameworků
  2. 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
  1. 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
  2. Podívejte se na atribut .textContent, protože automaticky zakóduje HTML entitu, pokud používáte javascript pro zápis do HTML
&    &amp;
< &lt;
> &gt;
" &quot;
' &#x27;

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
  1. Obklopte proměnné uvozovkami " nebo '
  • Uvozovky výrazně snižují množinu znaků, které je potřeba encodovat, což zvyšuje spolehlivost aplikace
  1. 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>
  1. Encodujte všechny znaky pomocí \xHH
  • Encoding knihovny často obsahují funkci EncodeForJavaScript nebo podobnou, která výše zmíněné podporuje
  1. 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>
  1. 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 >
  1. Ujistěte se, že jsou všechny atributy plně uvozeny jako v JS nebo CSS

Časté chyby

  1. Proveďte encoding URL a pak kódování HTML atributů
url = "https://site.com?data=" + urlencode(parameter)
<a href='attributeEncode(url)'>link</a>
  1. 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)
  1. 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)
  1. 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
    1. 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í
  1. Zkontrolujte, zda sanitizovaný řetězec “nezmutoval” před tím, než jej použijete
    • To je také považováno za nebezpečné
  2. 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í
  1. Zrefaktorujte kód tak, abyste odstranili reference na nezabezpečené sinks (innerHTML) a místo nich použijte textContent nebo value
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: alignalinkaltbgcolorbordercellpaddingcellspacingclasscolorcolscolspancoordsdirfaceheighthspaceismaplangmarginheightmarginwidthmultiplenohrefnoresizenoshadenowraprefrelrevrowsrowspanscrollingshapespansummarytabindextitleusemapvalignvaluevlinkvspacewidth

Další možnosti obrany

  • Framework, encoding výstupu a HTML sanitizace poskytnou nejlepší ochranu
    • Jsou doporučeny za všech okolností
  1. 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

Shrnutí pravidel prevence XSS

Datový typKontextCode sampleObrana
StringHTML bodyUNTRUSTED DATA HTML entity encoding
StringBezpeč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)
StringGET parametr<a href="/site/search?value=UNTRUSTED DATA ">clickme</a>URL encoding
StringNedů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
StringCSS hodnotaHTML <div style="width: UNTRUSTED DATA ;">Selection</div>1. Validujte strukturu 2. Hexadecimálně encodujte 3. Pečlivě navrhněte CSS funkcionalitu
StringJavascript 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
StringHTML body<div>UNTRUSTED HTML</div>Validujte HTML (JSoup, AntiSamy)
StringDOM 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 typEncoding mechanismus
HTML entity encodingPřevádí & na &amp, < na &lt, > na &gt, atd.
Encoding HTML atributuEncoduje všechny znaky pomocí &#HH; (hexadecimálně), kromě alfanumerických znaků
URL encodingStandardní kódování pomocí procent, viz https://www.w3schools.com/tags/ref_urlencode.asp
Javascript encodingEncoduje všechny znaky pomocí \uXXXX unicode kódování (X = integer), kromě alfanumerických znaků
CSS Hex encodingPodporuje \XX a \XXXXXX