HTML tag jako odjištěná zbraň

5. listopadu 2002

V článku „Bezpečnost především – zamezení interpretace HTML kódu“ jste se mohli dovědět, jak nebezpečný může být uživatel, je-li mu například na diskuzním fóru napsaném v PHP vložena do rukou zbraň v podobě formátování příspěvku pomocí XHTML elementů. Jaké jsou tedy „bezpečné“ možnosti formátování příspěvků na různých typech diskuzních fór?

Jenom pro připomenutí, dejme tomu, že uživateli dovolíme používat tag <b&gt a zbytek budeme filtrovat pomocí funkce string strip_tags(string retezec,[string povolene_tagy]). Pak následující kód způsobí katastrofu:

    <b style=“width: 100%;“ onmouseover=“document.location=’http://www.interval.cz'“>nějaký text</b>

Tento zápis nechá strip_tags bez povšimnutí. Jak určitě tušíte, vznikne tak řádek přes celou obrazovku, který vás po přejetí myší odešle na libovolný jiný web, což rozhodně žádného webmastera příliš nepotěší. Je sice pravda, že 95 % vašich návštěvníků určitě nikdy nenapadne něco takového do fóra zapisovat, přesto nemůžeme ani tuto možnost nechat bez povšimnutí, neboť v podstatě umožňuje na stránce spouštět libovolný JavaScript! Další, tentokrát již pravděpodobnější nevýhodou XHTML tagu, je dodržování W3C standardů. Uživatele samozřejmě příliš nezajímá, že jím vložené tagy nejsou podle dané normy. Často se tak stává, že vloží např. <B> namísto <b>, nebo jej neuzavře. Kapitolou samou pro sebe jsou pak vkládané odkazy <a>, které mohou kompletně narušit funkčnost fóra, zůstanou-li neukončeny. O tom, že uživatel často neuzavře argument do závorek, jak velí XHTML norma, mluvit netřeba.

Vlastní syntaxe

Jednou z možností řešení tohoto problému je pečlivá kontrola odeslaného příspěvku. To však nepovažuji za optimální řešení, neboť takto budete muset naprogramovat kontrolu počítající i s tou nejméně pravděpodobnou variantou, kterou si uživatel jenom může vymyslet. Proto je mnohem výhodnější a hlavně bezpečnější vytvořit vlastní syntaxi formátování příspěvku. Daná syntaxe by měla být co nejjednodušší a nejsrozumitelnější a uživatel by s ní měl být dobře obeznámen.

Navrhněme si takovou syntaxi:

  • {b}text{/} ~ vypíše text tlustě
  • {i}text{/} ~ vypíše text kurzívou
  • {adresa}text{/} ~ vytvoří z textu odkaz na danou adresu (řetězec adresa musí začínat http://)

Naším dalším úkolem je napsat PHP skript, který dané formátovací značky převede na XHTML tagy.

Některé funkce PHP pro práci s textem

Nejdříve si připomeňme některé funkce PHP pro náhradu části textu za jiný. Nejjednodušší je string str_replace(string vzorek, string nahrada, string retezec), která nahradí všechny výskyty řetězce vzorek řetezcem nahrada v řetězci retezec. Další funkce jsou založeny na regulárních výrazech:

    string ereg_replace (string vyraz, string nahrada, string retezec)
    string eregi_replace (string vyraz, string nahrada, string retezec)

Obě funkce pracují podobně jako zmíněná str_replace. Argument vyraz ovšem tentokrát není statický text, ale regulární výraz (o regulárních výrazech pojednává např. článek Regulární výrazy v PHP (1.)). Funkce tedy vyhledá v řetězci retezec všechny části odpovídající regulárnímu výrazu vyraz a nahradí je řetězcem nahrada. Funkce eregi_replace navíc není citlivá na malá a velká písmena.

Poslední funkci, kterou zde zmíním, je mixed preg_replace (mixed vyraz, mixed nahrada, mixed retezec). Funkce pracuje podobně jako ereg_replace, ovšem všechny argumenty mohou být pole řetězců, což znamená, že lze najednou provést náhradu pro všechny položky pole retezec najednou. Zároveň lze nadefinovat i více výrazů a jim příslušné náhrady (intuitivně n-tému prvku pole vyraz přísluší n-tý prvek pole nahrada).

Funkci str_replace použijeme, pokud předem známe přesné znění podřetězců, které potřebujeme vyhledat a nahradit. Naopak funkce používající regulární výrazy jsou výhodné, pokud známe pouze formát vyhledávaných podřetězců, nikoli jejich přesné znění. Nutno dodat, že str_replace je mnohem rychlejší než její protějšky pro regulární výrazy, a proto by měla být použita pokaždé, kdy je to jen možné.

Implementace navržené syntaxe

Pro implementaci použijeme regulární výrazy. Začněme zvýrazněným textem:

    $text=ereg_replace(„{b}([^{}]*){/}“,“<b>\\1</b>“,$text);

Hledáme vzorek odpovídající regulárnímu výrazu {b}([^{}]){/} (posloupnost znaků {b} následována libovolným řetězcem neobsahující složenou závorku a zakončená {/}), který nahradíme <b>\\1</b> (\\1 značí obsah části regulárního výrazu vymezený kulatými závorkami v prvním argumentu funkce). Tento postup můžeme udělat ještě více „odolným“, pokud budeme předpokládat, že se uživateli může vloudit mezera do složené závorky a že může použít velké písmeno namísto malého:

    $text=eregi_replace(„{ *b *}([^{}]*){ */ *}“,“<b>\\1</b>“,$text);

Regulární výraz { *b *} představuje „složenou závorku, žádná nebo více mezer, znak „b“, žádná nebo více mezer a složenou závorku“. Použitím funkce eregi_replace jsme uživateli dovolili použít velká písmena oproti námi definované syntaxi.

Obdobným způsobem vyřešíme text psaný kurzívou:

    $text=eregi_replace(„{ *i *}([^{}]*){ */ *}“,“<i>\\1</i>“,$text);

Vkládané odkazy jdou vyřešit dvojím způsobem. Jednak můžeme prohledávat celý příspěvek, vyhledávat odkazy a automaticky je transformovat na XHTML tagy. Zabývejme se ale naší speciální syntaxí. PHP kód je následující:

    $text=eregi_replace(„{ *(http://[^}]+) *}([^{}]+){ */ *}“,“<a href=\“\\1\“>\\2</a>“,$text);

Jak již bylo řečeno, předpokládáme, že uživatel svůj odkaz začne řetězcem http://. Do prvních kulatých závorek jsme tedy uzavřeli samotnou adresu, do druhých text, který se stane odkazem.

UBB-code

Nyní se podívejme na speciální syntaxi v praxi. Jeden z nejznámějších a nejlepších systémů Ultimate Bulletin Board system (UBB) používá pro formátování příspěvků svůj vlastní UBB-code. Jde o syntaxi podobnou HTML používající hranaté závorky místo špičatých. Zde je ukázka:

  • [B]tučný text[/B]
  • [I]kurzíva[/I]
  • [URL=http://www.interval.cz]odkaz[/URL]
  • [EMAIL]email[/EMAIL]
  • [IMG]adresa nějakého obrázku[/IMG]
  • [QUOTE]citát[/QUOTE]

Výhody a nevýhody speciální syntaxe

Výhody jsou myslím zřejmé. Uživatel nemá možnost vkládat spustitelný, resp. interpretovatelný obsah do svých příspěvků, protože je plně pod vaší kontrolou, jak se kód zapsaný ve speciální syntaxi převede na XHTML. Další výhodou je, že špatně zapsaná část kódu nijak neohrozí vaši aplikaci. Zatímco např. neukončený odkaz způsobí pohromu, jeho protějšek ve speciální syntaxi se pouze zobrazí ve výsledném výpise fóra, což z hlediska funkčnosti fóra nijak neuškodí. A navíc, pokud je uživateli umožněno svůj příspěvek upravovat (což je asi reálně uskutečnitelné pouze na fórech s registrací), může si chybné zapsání syntaxe uvědomit a opravit. Snad jedinou skutečnou nevýhodou tohoto postupu je nutnost uživatele dobře seznámit se syntaxí a zařídit, aby byla „po ruce“ např. i přímo při psaní příspěvku.

Speciální syntaxe je asi nejlepší možnost, jak co nejlépe zabezpečit diskuzní fórum a zároveň dovolit uživateli formátovat své příspěvky.

Starší komentáře ke článku

Pokud máte zájem o starší komentáře k tomuto článku, naleznete je zde.

Štítky: Články

Mohlo by vás také zajímat

Nejnovější

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *