Přeskočit na hlavní obsah

Aplikační data čistá jako lilie

V článku o Cross-site scriptingu jsem se dotkl myšlenky, že není vhodné na začátku skriptu prohánět vstupní parametry funkcí htmlspecialchars(). Doporučoval jsem místo toho aplikovat toto ošetření až bezprostředně při odesílání dat na výstup. Rád bych nyní téma blíže rozvedl. Proč je paušální použití zmíněné funkce na začátku aplikace špatné?

Už zase to MVC

Pro pochopení, v čem je chyba, si představte klasickou MVC architekturu. Na stejné systémové rozpory nakonec narazíte snad i při jakékoliv jiné architektuře, ale na MVC je to vidět snad nejlépe.

V architektuře MVC se aplikace sestává ze tří částí – Modelu, View a Controlleru. Zjednodušeně řečeno Controller zajišťuje interakci vůči požadavkům uživatelů a jejich primární zpracování. Model poskytuje business logiku a veškerou manipulaci s aplikačními daty. View pak výstup na zobrazovací zařízení uživatele.

Základní myšlenkou MVC je předpoklad, že když kteroukoliv z těchto částí vyměníte či nahradíte, nemělo by to nijak ovlivnit zbývající dvě části. Většina webových aplikací tak má View zajišťující HTML výstup do prohlížeče. Pokud jej ale nahradím jiným, které poskytuje třeba výstup do WML, odpověď přes SOAP nebo export do PDF, mělo by to být možné, aniž bych musel cokoliv měnit v Modelu nebo Controlleru.

Kontaminujeme aplikační data

Celý problém je už asi zjevný. Funkce htmlspecialchars() je totiž úzce svázána jen a pouze s výstupem do HTML. Patří tedy ze své podstaty do View generujícího webové stránky. Nikde jinde v aplikaci nemá co dělat.

Když ji použijeme na vstupní data hned na začátku běhu aplikace (tedy v Controlleru či Modelu), kontaminujeme si veškerá aplikační data balastem, který je svázán jen s HTML formátem výstupu. Například z názvu firmy Pepa & syn budeme mít v databázi uložené Pepa & syn.

Budu-li chtít později vygenerovat třeba PDF soubor, mám zásadní problém. Musím předtím nějak všechny &, " a jim podobné textové entity pracně nesystémově nahrazovat zpět za původní znaky.

Vše má své místo

Správné řešení je jen jedno – systémově aplikovat všechna ošetření právě na těch místech, kam patří. Pokud je cokoliv svázáno s konkrétním typem výstupu, je nutné to aplikovat právě až při generování daného výstupu.

Do Modelu a tím potažmo i do databáze patří pouze čistá aplikační data, nezatížená a nekontaminovaná jakýmkoliv konkrétním typem View. Jenom tak budou připravena pro výstup do jakéhokoliv dnešního i budoucího formátu.

Proklatě magické uvozovky

Ze podobného soudku je fungování direktivy magic_quotes_gpc. Měla původně chránit aplikace před SQL injection tím, že ve vstupních datech opatří všechny citlivé znaky zpětným lomítkem, čímž z hlediska databáze zruší jejich speciální význam. To má ale smysl dělat až bezprostředně při vkládání vstupních dat do SQL dotazu:

mysql_query('SELECT *
FROM uzivatele
WHERE jmeno = "' . mysql_real_escape_string($_GET['jmeno']) . '"');

Tím, že mechanizmus magic_quotes_gpc ošetřuje paušálně všechna vstupní data, a navíc ještě před začátkem provádění samotného skriptu, zanáší do aplikace nesystémovost popisovanou v tomto článku. V důsledku toho pak máme v aplikaci proměnné plné zpětných lomítek, která tam vůbec nemají co dělat.

echo $_GET['id'];

Pokud uvedený skript zavolám s parametrem ?id=joe's garage, aplikace mi při zapnuté direktivě vypíše joe\'s garage. Kdybych chtěl získat to, co uživatel opravdu zadal, tedy joe's garage, musím celý parametr explicitně prohnat funkcí stripslashes(). To je ale samozřejmě úplně postavené na hlavu jakožto důsledek celé nesystémovosti takového řešení.

HTML do databáze nepatří

Dalším obdobným příkladem nevhodného postupu je ukládání vlastně jakéhokoliv HTML kódu do databáze. Ani ten tam logicky nepatří, protože je opět spojen s jedním typem výstupu. A při generování nějakého e-mailu nebo PDF bych musel opět řešit, jak se vypořádat s uloženými HTML tagy apod. Je ovšem pravda, že zrovna tady praktická stránka věci bohužel většinou vítězí nad snahou o systémovou čistotu a třeba při ukládání článků v CMS sypou HTML do databáze skoro všichni.

Radši ale upozorním na jednu věc. Pokud říkám, že HTML kód nepatří do databáze, myslím tím databázi v rámci Modelu, neboli v rámci základních aplikačních dat.

Jsou ale případy, kdy je ukládání HTML kódu nebo dat prohnaných skrz htmlspecialchars() zcela v pořádku. Mám na mysli typicky databázové cachování částí vygenerovaného kódu nebo i celých výstupních stránek. Tady je ovšem nutné si uvědomit, že tato část databáze nepatří do modelu, ale je jakoby součástí View.

Napište komentář

  • Jméno a e-mail jsou povinné. E-mail nebude zobrazen.
  • V textu komentáře můžete používat Texy!
  • Tykejme si.
  • Příležitostné mazání zhůvěřilých komentářů nevylučuji.