Cross Site Scripting

Školení, která pořádám

XSS je způsob narušení webových stránek, kdy je útočník modifikuje tak, že se v jejich kontextu provede podstrčený JavaScriptový kód. Tomuto typu útoku se dá poměrně jednoduše bránit ošetřováním vypisovaných dat, u kterých si nemůžeme být jisti jejich hodnotou – ručně nebo automaticky využitím šablonovacího systému. Typicky to jsou data, která dostaneme od uživatele metodou GET, POST nebo v cookie. Stejně tak je pochopitelně nutné ošetřovat i data od uživatele, která jsme si uložili do databáze a následně je vypisujeme. Uživatel může změnit i některé hodnoty v poli $_SERVER (např. PHP_SELF a za určitých okolností i SERVER_NAME), měli bychom tedy ošetřovat i je.

Data bychom měli ošetřovat s touto prioritou:

  1. Data, která se zobrazují i ostatním uživatelům (např. diskusní příspěvky nebo položky zobrazované v TOP 10 nebo RECENT 10) – neošetření může znamenat třeba riziko krádeže přihlašovacích údajů.
  2. Data, která zadá uživatel a zobrazí se jen jemu (např. registrační údaje) – neošetření může způsobit špatné vypsání zadaných údajů.
  3. Data, která si sami posíláme v parametrech a na stránce následně zobrazujeme (např. ID článku) – ošetřením těchto dat můžeme uživatele ochránit před phishingem.

Data naopak není třeba ošetřovat, pokud pocházejí z důvěryhodného zdroje – např. pokud vypisujeme číselný sloupec z databáze (pokud se ovšem nejedná o SQLite, která umožňuje do číselného sloupce uložit i speciální znaky…).

Přijďte si o tomto tématu popovídat na školení Bezpečnost PHP aplikací (22.3.2017, Praha).

Jakub Vrána, Výuka, 23.11.2005, diskuse: 9 (nové: 0)

Diskuse

Radek Domín:

Podle mého názoru je nutné se o validaci dat starat už před vstupem do databáze a ne až při výstupu.

Myslím také, že správné je nenechávat tuto starost na šablonovém systému (tedy na výstupní vrstvě). V ideálním případě by se o validaci měl starat samostatný objekt (validátor).

Llaik:

Ale oboje je preci o necem jinem.
Pri vstupu do db si typicky hlidam uvozovky.
Pri vystupu do html stranky si zase hlidam zobaky.

Je dost neprakticky hlidat zobaku uz pred vstupem do db (napriklad pak ztraci na vyznamu zjistovani delky ulozeneho textu), protoze to je vec prezencni vrstvy - tedy napriklad sablon - kolikrat mam jednu sablonu a jednou ji chci vypsat osetrenou a podruhe nikoliv (ve stejne strance, i takove veci se deji :)). Pak to opravdu uz musim nechat na prezencni vrstve.

ikona Jakub Vrána OpenID:

Přesně jak píše Llaik - validaci samozřejmě už na vstupu, ale ošetření pro konkrétní výstup až na výstupu. O úskalích ošetřování při ukládání jsem už psal - http://php.vrana.cz/escapovani.php - kromě tam zmíněných důvodů je také někdy potřeba uložená data použít k něčemu jinému než k výstupu do HTML.

burro.b:

Mě se poslední dobou osvědčuje zpracovávat údaje ještě před uložením vstupu do databáze, vždy si vyrobím fci která upraví text na požadovaný formát(nahrazení všeho povoleného, pak /nuceně/ zalámu řádky tam kde by mohly zlobit /třeba 30+ znaků, prostě no-overflow/, finálně htmlspecialchars() a překódování do výstupního character-setu/utf-8.../)

Jakub Podhorský:

ale jak potom řešíš situaci když potřebuješ tyhle data upravovat? to máš potom v tom formuláři změť přebytečných tagů a značek

teda pokud si to opět nevrátíš pomocí nějaké funkce do původního stavu, ale v tom případě se mi to zdá jako naprosto zbytečný krok

anode:

No jednu výhodu v tom vidím - nemůže se mi stát, že jednou ty data při výpisu zapomenu upravit do bezpečné formy. Navíc argument o rychlosti je trochu lichý - mnohem častěji se bude obsah zobrazovat, tedy výstupní filtr se provádí daleko častěji než vstupní. Výstupní filtr se uplatní, pokud se filtr často mění, ale z hlediska výkonu a bezpečnosti je jasně lepší vstupní filtr.

Llaik:

Vyhoda je, ze to zabrani tvemu lajdactvi? :)
Rychlost zavolani htmlspecialchars() je v ramci cele stranky naprosto zanedbatelna.

Vstupni filtr mi dela cachry nejenom s delkou - ja opravdu nekdy ta data nechci mit htmlescapovana - napriklad pokud je opravdu chci zobrazit jako volne html :) co kdyz se jednou zmeni redakcni system? Co kdyz...?

At koukam na rychlost htmlspecialchars() v profileru jak koukam, tak tam zadny vykonovy problem nevidim. Vic bych se bal nejakeho regularniho vyrazu, cyklu, sql dotazu, ...

anode:

Lajdactvi? Pri kazdem vypisu z db ty data prohanet pres htmlspecialchars(), to je jen dalsi vec, na kterou musim myslet, dalsi technicky problem, ktery nijak nesouvisi s tim, co chci s temi daty dal delat. Proto treba pouzivam tridu pro strankovani vypisu z databaze, tridu pro praci s XML soubory, abych se mohl soustredit na to, co chci delat, ne na technicke podruznosti jako otevreni souboru, kontrola otevreni, parsovani elementu...

Nevim, jestli bude nekoho zajimat presna delka clanku. Pokud chci zabranit XSS (o kterem je tenhle clanek), nebudu prece vypisovat volne HTML. Zmena RS nema vliv, kdyz preferuji vstupni filtrovani, napisu tak i novy RS :)

Kdyz jsem mluvil o rychlosti, mel jsem na mysli filtrovani obecne. Jisteze je rychlost zavolani htmlspecialchars() zanedbatelna, az budu chtit pouzit jiny filtr, ktery si treba sam napisu, muze byt uspora casu znacnejsi. Co kdyz... :) Jenom jsem narazel na "naprosto zbytečný krok"...

ikona Jakub Vrána OpenID:

Pokud se chceš vyhnout riziku zapomenutí na HTML escapování na výstupu, můžeš použít šablonovací systém, kde se escapuje standardně a pokud chceš nějaká data vypsat syrová, musíš si na to naopak vzpomenout.

V rychlosti problém opravdu není, jak už tady bylo zmíněno.

Vložit komentář

Používejte diakritiku. Vstup se chápe jako čistý text, ale URL budou převedeny na odkazy a PHP kód uzavřený do <?php ?> bude zvýrazněn. Pokud máte dotaz, který nesouvisí s článkem, zkuste raději diskusi o PHP, zde se odpovědi pravděpodobně nedočkáte.

Jméno: URL:

avatar © 2005-2017 Jakub Vrána. Publikované texty můžete přetiskovat pouze se svolením autora. Ukázky kódu smíte používat s uvedením autora a URL tohoto webu bez dalších omezení Creative Commons. Můžeme si tykat. Skripty předpokládají nastavení: magic_quotes_gpc=Off, magic_quotes_runtime=Off, error_reporting=E_ALL & ~E_NOTICE a očekávají předchozí zavolání mysql_set_charset. Skripty by měly být funkční v PHP >= 4.3 a PHP >= 5.0.