Internet Info, s.r.o. Lupa Měšec Podnikatel Root Zdroják DigiZone Slunečnice Vitalia TopDrive KupDnes Navrcholu NovýTarif Dobrý web Weblogy Woko Jagg Computer.cz SK: MojeLinky

Hlavní navigace

Co je Cross-site scripting jak mu předcházet

XSS neboli Cross-Site Scripting je jedna z nejstarších zranitelností webových aplikací. A protože jí stále mnoho webů, resp. webových aplikací trpí a většina uživatelů má JavaScript zapnutý, ukážeme si jednoduché příklady, jak zranitelnost vzniká a jak se jí bránit. Článek je věnován zejména těm, kdo o XSS zatím pořádně neslyšeli.

Tweetni to Twitter Jaggni to! Jagg Del.icio.us Delicious

V tomto článku budeme vyžadovat alespoň základní znalosti HTML, CSS a JavaScriptu. Pro serverově orientované příklady byl zvolen značkovací jazyk PHP pro jeho jednoduchost a rozšířenost.

Na úvod: co mohou způsobit znaky „<“ a „>“

Začneme příkladem. Mějme jednoduchou stránku s jedním vstupním polem, které je součástí formuláře. Formulář odesílá svůj obsah na stejnou stránku a zobrazí obsah odeslaného políčka.

<html>
<body>
  <form>
    <input type="text" name="test">
    <input type="submit" value="Odeslat a zobrazit">
  <br>
<?php
if (isset($_GET['test'])) {
    echo 'Odeslaná hodnota je: ' . $_GET['test'];
}
?>
  </form>
</body>
</html> 

Co se stane, když do našeho formuláře zadáte slovo „pokus“? Na výsledné stránce se zobrazí slovo „pokus“. Co se ovšem stane, když k němu přidáte značky HTML a zadáte např. „<b>pokus</b>“? Zobrazí se tučně slovo „pokus“.

Jinými slovy – v tomto případě můžete libovolně měnit HTML stránku. Uvedený příklad je jedním z mnoha případů XSS. Kromě celkem neškodné značky pro tučné písmo můžete vložit i kód spouštějící JavaScript (odtud také pochází název Cross-Site Scripting). Podívejte se na několik ukázek možných vstupů a na jejich výsledky (možností je ale daleko víc):

uživatelský vstup akce v prohlížeči
<b>pokus</b> zobrazí se „pokus“ (tučně)
<img src=x onerror=„aler­t(‚XSS‘);“> vyskočí javascriptové okno s nápisem XSS
<img src=„http://h­acker.example­.cz“> zobrazí se obrázek z útočníkovy stránky

Jak se útoku bránit? V našem případě postačí, když nahradíme znaky „<“ a „>“ HTML entitami, tedy „&lt;“ a „&gt;“.

Pro začátek předvedeme tu nejjednodušší funkci, která je k dispozici snad v každém programovacím jazyce – nahrazování výskytu řetězce za jiný – v PHP je to str_replace. Uvedený kód tedy změníme na následující:

echo 'Odeslaná hodnota je: ' . str_replace(array('<', '>'), array('&lt;', '&gt;'), $_GET['test']); 

Tím jsem uvedený příklad ochránil proti XSS. Ale pozor, tato obrana není v některých případech dostačující. Proto čtěte dál.

Co může způsobit uvozovka nebo apostrof

Rozšíříme předchozí příklad – pro snadnou změnu během testování zobrazíme odeslanou hodnotu i v textovém poli.

<html>
<body>
  <form>
    <input type="text" name="test" value="<?php echo $_GET['test']; ?>">
    <input type="submit" value="Odeslat a zobrazit">
    <br>
<?php
if (isset($_GET['test'])) {
        echo 'Odeslaná hodnota je: ' . $_GET['test'];
}
?>
  </form>
</body>
</html> 

Po vyzkoušení uživatelských vstupů z první tabulky se může zdát, že je vše v pořádku. Ale to je omyl, viz následující vstupy:

uživatelský vstup akce v prohlížeči
„><img src=“http://h­acker.example­.cz/obrazek.jpg"><x x=" zobrazí se obrázek z útočníkova serveru
" onclick=„aler­t(‚XSS‘);“ x=" vyskočí javascriptové okno po kliknutí do políčka

Kromě znaků „<“ a „>“ musíme totiž ošetřit i uvozovky (") a apostrofy ('), podle toho, co používáme. V PHP se pro tento účel používá funkce htmlspecialchar­s().

<input type="text" name="test" value="<?php echo htmlspecialchars($_GET['test'], ENT_QUOTES); ?>"> 

Co v případě značky textarea?

V dalším příkladu předvedeme ještě jedno ošetření HTML, kde nemusí být na první pohled jasné, proč jej vůbec dělat. Na první pohled se totiž může zdát, že není nutné nic ošetřovat. Mějme následující příklad:

<html>
<body>
  <form>
    <textarea name="test"><?php echo $_GET['test']; ?></textarea>
    <input type="submit" value="Odeslat a zobrazit">
  </form>
</body>
</html> 

Pokud budete zkoušet prozatím uvedené uživatelské vstupy, značku textarea neprolomíte. Zkuste ale dodat do uživatelského vstupu její vlastní uzavírací značku.

uživatelský vstup akce v prohlížeči
</textarea><img src=„http://h­acker.example­.cz/obrazek.jpg“> zobrazí se obrázek z útočníkova serveru

A obrana? Jako v prvním příkladu – převádět znaky „<“ a „>“ na jejich HTML entity, například pomocí funkce htmlspecialchar­s().

Obrana v samotném JavaScriptu

Výše uvedené příklady měly jedno společné – uživatelský vstup se ošetřoval na straně serveru. A co když nás serverová strana zrovna nezajímá, můžeme si nezabezpečená data ošetřit i na klientské straně? Ano, i to jde, ukážeme si další příklad:

<html>
<body>
  <script>
    function zobraz() {
      document.getElementById('vysledek').innerHTML =
           'Odeslaná hodnota je: ' +
           document.getElementById('test').value;
      }
  </script>

  <input type="text" id="test">
  <input type="submit" onclick="zobraz();" value="Zobrazit">
  <br>
  <div id="vysledek"></div>
</body>
</html> 

V příkladu je použita metoda innerHTML(), ta umožňuje upravit (resp. nahradit) část HTML dokumentu. Vyzkoušejme následující vstupy:

uživatelský vstup akce v prohlížeči
pokus zobrazí se „pokus“
<b>pokus</b> zobrazí se „pokus“ (tučně)
<img src=„http://h­acker.example­.cz“> zobrazí se obrázek z útočníkova serveru
<b onmouseover=„a­lert(‚XSS‘);“>n­ajeď myší přes tento text</b> vyskočí javascriptové okno s nápisem XSS

Obrana je stejná jako u prvního příkladu: nahradíme nebezpečné znaky jejich HTML entitami. V JavaScriptu použijeme metodu replace().

function zobraz() {
document.getElementById('vysledek').innerHTML =
       'Odeslaná hodnota je: ' +
       document.getElementById('test').value.replace(/</g, '&lt;').replace(/>/g, '&gt;');
} 

Míchanice: HTML + PHP + JavaScript

PHP svou jednoduchostí přímo svádí k míchání kódu (např. v samotném HTML použijeme pro výpis hodnot PHP), a tak snad nepřekvapí ani generování JavaScriptu z PHP. Může se někdy samozřejmě hodit, ale opět je nutné si dát pozor.

<html>
<body>
<script>
  window.onload = function() {
    var value = 'Odeslaná hodnota je: <?php echo $_GET['test']; ?>';
    value = value.replace(/</g, '&lt;').replace(/>/g, '&gt;');
    document.getElementById('vysledek').innerHTML = value;
  }
</script>

  <form>
    <input type="text" name="test">
    <input type="submit" value="Odeslat">
    <div id="vysledek"></div>
  </form>
</body>
</html> 

Zobrazení hodnoty je zde již ošetřeno. Ale podle předchozích zkušeností s uvozovkami a apostrofy nás hned napadne, jak apostrof prolomit.

uživatelský vstup akce v prohlížeči
'; alert(„XSS“); value = 'není tu nic vyskočí javascriptové okno s nápisem XSS

Pokusíme se tedy ošetřit apostrofy a uvozovky, ale pozor, to není celá obrana. Existuje totiž další možnost, jak JavaScript ukončit. Je to značka pro ukončení skriptu: „</script>“ nebo i její kratší varianta "</script " (mezera či jakýkoliv jiný prázdný znak na konci). Jakmile interpret JavaScriptu narazí na tento výskyt znaků, ukončí se javascript a dále se pokračuje ve zpracování HTML.

uživatelský vstup akce v prohlížeči
</script><scrip­t>alert(„XSS“)</sc­ript> vyskočí javascriptové okno s nápisem XSS
</script><img src=„http://h­acker.example­.cz“> zobrazí se obrázek z útočníkovy stránky

A jak se bránit v tomto případě? Nejjednodušší je opět nahradit „nebezpečné znaky“: < a > za jejich HTML entity.

Další případ: uživatelským vstupem je HTML

Výše uvedené příklady pracovaly jen s prostým textem a cílem bylo jej zobrazit. Existují situace, kdy uživatelským vstupem skutečně je HTML, typickým případem může být webové rozhraní e-mailu. Zde vyvstává řada dalších otázek:

  • Co s nevalidním HTML?
  • Budou se zobrazovat externí obrázky?
  • Povolíme kaskádové styly?
  • Co s JavaScriptem?
  • Co s formuláři?
  • … (a řada dalších)

Na jednu stranu chceme zajistit bezpečnost a na druhou stranu uživatel chce mít „hezky vypadající e-mail“ – prostě HTML. Existuje více způsobů, jak řešit tento problém, ale nejúčinnějším řešením je použití tzv. whitelistu – seznamu HTML značek a jejich atributů, jejichž vložení povolíme (protože jsou bezpečné). Příklad takového velmi krátkého whitelistu:

povolená značka povolený atribut
p
a href
b

Odpovíme na předchozí otázky s pomocí této tabulky:

  • Co s nevalidním HTML?
    Nevalidní HTML budeme muset nejdříve převést na validní HTML (pokud je tedy nechceme rovnou zahodit). Prohlížeče to také řeší (a bohužel každý trochu jinak), ideálně k tomu použijeme nějakou hotovou knihovnu.
  • Budou se zobrazovat externí obrázky?
    Ne, značka „img“ není v našem whitelistu povolena.
  • Povolíme kaskádové styly?
    Ne, značka „link“ pro načtení externího stylopisu není povolena, ani atribut „style“ není povolen.
  • Co s JavaScriptem?
    Odfiltruje se. Značka „script“ není povolena ani žádné atributy využitelné jako ovladače událostí nejsou povoleny (příkladem může být „onclick“) ani kaskádové styly nejsou povoleny (i ty by mohly vést ke spuštění JavaScriptu, viz níže). Nesmíme ovšem zapomenout zkontrolovat i obsah povoleného atributu href (ten by mohl obsahovat javascriptový kód uvozený prefixem „javascript:“)
  • Co s formuláři?
    Odfiltrují se. Značky „form“, „input“ ani další formulářové značky nejsou povoleny.

Z košatého HTML na vstupu se zahodí veškeré nepovolené HTML značky a atributy. Zůstanou jen ty povolené.

XSS a kaskádové styly

Kaskádové styly úzce souvisí s předchozí problematikou zobrazování uživatelského HTML. I zde existují možnosti, jak útočit a např. spustit JavaScript. Příkladem může být vlastnost expression dostupná v Internet Exploreru:

<div style="width: expression(alert('XSS'));"> 

Pro Firefox (a všechny prohlížeče postavené na jádru Gecko) existuje v kaskádových stylech také vlastnost, která umožňuje spuštění JavaScriptu (podrobnosti najdete v XSS Cheat Sheet), viz příklad:

<p style=-moz-binding:url(xssByCssInFirefox.xml#xss);>text</p> 

Řešení? Podobně jako v předchozím příkladu: whitelist, čili povolit jen ty vlastnosti, které opravdu povolit chceme.

Napsat vlastní HTML/CSS filtr není nic jednoduchého, proto pravděpodobně použijete nějakou hotovou knihovnu, v případě PHP např. projekt HTML Purifier.

Závěr

Tvůrci webů a webových aplikací by měli myslet na bezpečnost a nezapomínat pečlivě ošetřovat veškeré vstupy od uživatelů. Veškeré možné útoky včetně jejich podpory v nejpoužívanějších prohlížečích se dají nastudovat na XSS Cheat Sheet od RSnake.

TIB2012

       

Uživatelé Firefoxu se pak mohou chránit proti mnoha typům XSS pomocí rozšíření NoScript. Má však zpočátku otravnou, ale jinak velmi účinnou, vlastnost. Musíte NoScript nejdříve naučit, jaké weby mohou používat JavaScript ve vašem prohlížeči.

Odkazy


Autorem článku je Jan Pejša, vývojář webových aplikací ve společnosti Kerio Technologies s.r.o., která je jedním z hlavních výrobců bezpečnostního internetového softwaru pro malé a středně rozsáhlé sítě, se specializací na síťové firewally a bezpečnost interní firemní komunikace.

Jan Pejša

Absolvent ZČU v Plzni. V současné době pracuje jako vývojář webových aplikací ve společnosti Kerio Technologies s.r.o..

Kurz SEO - Praha, Brno

DW - Školení SEO
  • Jak fungují vyhledávače a co od nich můžete očekávat.
  • Analýza klíčových slov - kde hledat, jak slova vybrat, jak optimalizovat.
  • Metody linkbuildingu - jak získat zpětné odkazy aniž byste za ně museli platit.
  • Vyhodnocování SEO - nesledujte jen pozice.

Další informace o kurzu SEO »

Akce: Využijte last minute slevu na školení v Brně!

Přehled názorů

RE: Co je Cross-site scripting jak mu předcházet
danaketh 5. 3. 2009 01:37
Nový
└ 
RE: Co je Cross-site scripting jak mu předcházet
Keson 5. 3. 2009 02:30
Nový
 
└ 
RE: Co je Cross-site scripting jak mu předcházet
benzin 9. 3. 2009 08:50
Nový
str_replace
dan 5. 3. 2009 07:52
Nový
└ 
Re: str_replace
Josef Moravec 5. 3. 2009 07:54
Nový
 
└ 
Re: str_replace
dan 5. 3. 2009 08:32
Nový
 
 
├ 
Re: str_replace
Hoween 5. 3. 2009 08:56
Nový
 
 
│
├ 
Re: str_replace
Miroslav Juhos 5. 3. 2009 10:12
Nový
 
 
│
├ 
Re: str_replace
SFS 5. 3. 2009 13:34
Nový
 
 
│
│
├ 
Re: str_replace
Hoween 5. 3. 2009 13:49
Nový
 
 
│
│
│
└ 
Re: str_replace
SFS 5. 3. 2009 14:02
Nový
 
 
│
│
└ 
Re: str_replace
dan 5. 3. 2009 13:50
Nový
 
 
│
│
 
└ 
Re: str_replace
SFS 5. 3. 2009 14:16
Nový
 
 
│
│
 
 
├ 
Re: str_replace
dan 5. 3. 2009 15:23
Nový
 
 
│
│
 
 
│
├ 
Re: str_replace
n0 5. 3. 2009 19:25
Nový
 
 
│
│
 
 
│
└ 
Re: str_replace
blek džek 5. 3. 2009 20:08
Nový
 
 
│
│
 
 
│
 
└ 
Re: str_replace
anonymní uživatel 6. 3. 2009 13:54
Nový
 
 
│
│
 
 
└ 
Re: str_replace
anonymní uživatel 6. 3. 2009 13:51
Nový
 
 
│
│
 
 
 
└ 
Re: str_replace
anonymní uživatel 6. 3. 2009 15:13
Nový
 
 
│
├ 
Re: str_replace
czexit 5. 3. 2009 19:54
Nový
 
 
│
└ 
Re: str_replace
Kuchař 21. 3. 2009 00:33
Nový
 
 
├ 
Re: str_replace
yossarian 5. 3. 2009 09:08
Nový
 
 
├ 
Re: str_replace
Jan Pejša 5. 3. 2009 09:17
Nový
 
 
│
└ 
Re: str_replace
Hoween 5. 3. 2009 09:27
Nový
 
 
│
 
└ 
Re: str_replace
noaco 5. 3. 2009 09:59
Nový
 
 
│
 
 
├ 
Re: str_replace
Hoween 5. 3. 2009 10:10
Nový
 
 
│
 
 
│
└ 
Re: str_replace
Martin 5. 3. 2009 13:11
Nový
 
 
│
 
 
│
 
└ 
Re: str_replace
Hoween 5. 3. 2009 13:20
Nový
 
 
│
 
 
└ 
Re: str_replace
jar 6. 3. 2009 08:39
Nový
 
 
│
 
 
 
└ 
Re: str_replace
Hoween 6. 3. 2009 09:00
Nový
 
 
├ 
Re: str_replace
Peter Helcmanovsky 5. 3. 2009 09:24
Nový
 
 
│
└ 
Re: str_replace
Hoween 5. 3. 2009 09:29
Nový
 
 
└ 
Re: str_replace
David Grudl 5. 3. 2009 15:08
Nový
prečítajte si tiež
Ja. 5. 3. 2009 08:19
Nový
└ 
Re: prečítajte si tiež
Martin Hassman 5. 3. 2009 08:39
Nový
Chyba v escapování pro JavaScript
David Grudl 5. 3. 2009 15:04
Nový
└ 
Re: Chyba v escapování pro JavaScript
Jan Pejša 5. 3. 2009 15:18
Nový
 
└ 
Re: Chyba v escapování pro JavaScript
David Grudl 5. 3. 2009 15:44
Nový
 
 
├ 
Re: Chyba v escapování pro JavaScript
David Grudl 5. 3. 2009 15:45
Nový
 
 
└ 
Re: Chyba v escapování pro JavaScript
Jan Pejša 5. 3. 2009 15:49
Nový
 
 
 
├ 
Re: Chyba v escapování pro JavaScript
Jakub Vrána 5. 3. 2009 15:58
Nový
 
 
 
└ 
Re: Chyba v escapování pro JavaScript
Jan Pejša 5. 3. 2009 21:10
Nový
Ošetření znaku &
David Grudl 5. 3. 2009 20:01
Nový
├ 
Re: Ošetření znaku &
Jan Pejša 5. 3. 2009 21:54
Nový
│
└ 
Re: Ošetření znaku &
Hoween 5. 3. 2009 22:12
Nový
│
 
└ 
Re: Ošetření znaku &
David Grudl 6. 3. 2009 02:44
Nový
└ 
Re: Ošetření znaku &
Jan Pejša 6. 3. 2009 10:46
Nový
 
└ 
Re: Ošetření znaku &
Jakub Vrána 6. 3. 2009 10:57
Nový
RE: Co je Cross-site scripting jak mu předcházet
Standa 5. 3. 2009 22:15
Nový
├ 
RE: Co je Cross-site scripting jak mu předcházet
Jan Pejša 6. 3. 2009 07:16
Nový
├ 
RE: Co je Cross-site scripting jak mu předcházet
Hoween 6. 3. 2009 08:23
Nový
└ 
RE: Co je Cross-site scripting jak mu předcházet
Karel Fučík 6. 3. 2009 10:58
Nový
Ještě jednou a tentokrát pořádně
David Grudl 6. 3. 2009 15:37
Nový
Jak bastlit pseudoochranu uživatelských vstupů.
Ash 6. 3. 2009 16:42
Nový
       

Tento text je již více než dva měsíce starý. Chcete-li na něj reagovat v diskusi, pravděpodobně vám již nikdo neodpoví. Pro řešení aktuálních problémů doporučujeme využít naše diskusní fórum.

Zasílat nově přidané příspěvky e-mailem