[ Webhosting profitux.cz ]
v6ak [ programování, bezpečnost, web, php, java, ... ] (Vít Šesták)
Buzz - v6ak Twitter - v6ak

štítky

Musí být na http vstupu jen string?

Máte-li GET/POST/COOKIE vstup, jste si jisti, že tam bude string, pokud tam něco bude? Nemusí tomu tak být! Může tam být například pole. A to může vést k různému nepředvídanému chování.

Píšu o tom, protože jde o často opomíjený problém.

Jak se tam dostane pole?

To je velmi jednoduché. Aspoň u GET/POST, u COOKIE jsem to nezkoušel. Jak říkal v komentáři Jakub Vrána a následně jsem si ověřil, platí to nejen u GET a POST, ale i u COOKIE. Teoreticky to závisí na platformě pro serverové skripty, v praxi je to snad všude stejně, jen nevím, jak se s tím vypořádají typové jazyky. Uvedené platí určitě pro PHP, zcela určitě pro ASP.NET a možná i pro další platformy.

Normálně totiž jsou hodnoty odeslány ve tvaru nazev1=hodnota1&nazev2=hodnota2. Buď za otazníkem v adrese, nebo v POSTDATA. Jenže lze napsat i nazev1[]=hodnota-1-0&nazev1[]=hodnota-1-1&nazev1[]=hodnota-1-2&nazev1[x]=hodnota-1-x. A tak se tam často dostane pole nazev1 s příslušnými prvky. V tomto případě dokonce asociativní pole. Nevěříte? Tak si to vyzkoušejte...

Tak můžu tam mít pole, řetězec. A ještě něco dašího?

Nevím o tom, ale ve skriptech bych to předpokládal. Je vždy lepší testovat, zda jde např. o řetězec (is_string(vstup)), než zda nejde o pole (!is_array(vstup)). Je to podobné tvrzení, jako že dobrý whitelist je vždy lepší, než dobrý blacklist, pokud nemáme dopředu uzavřenou množinu hodnot, která se určitě nebude rozšiřovat.

I kdyby to nebylo k ničemu, v praxi by to nemělo znamenat moc práce navíc.

Co to může způsobit?

Záleží na konkrétním případě - kam to cpete. Tedy na skriptu i na platformě pro serverové skripty. Někdy lze získat zajímavé informace.

Odkrytí implementace nebo zdrojáku

ASP.NET

O tom, že pole může udělat pěknou neplechu, se můžete přesvědčit hlavně u ASP.NET. Záleží pochopitelně na konfiguraci, ale i tak se najdou servery, které mají nastavený docela sdílný režim. Nevěříte?

aspx.png, 37 kB

Měli byste! Zjistit část zdrojáku je tak velmi jednoduché. V tomto případě mi po dalším zkoumání moc nechybělo k získání zajímavých údajů. (Některé údaje na obrázku jsou z pochopitelných důvodů úmyslně rozmazané a lišta panelů je vypuštěna.)

PHP

Představte si následjící jednoduchý kód:

<?php header('content-type:text/plain; charset=utf-8'); if(!isset($_GET['a'])){ die('Chci a!'); }; echo "\n".'---'."\n"; echo htmlspecialchars($_GET['a']); echo "\n".'---'."\n"; echo htmlspecialchars($_GET['a'].'b'); echo "\n".'---'."\n"; echo addslashes($_GET['a']);

Pro GET vstup a[]=s Může vypsat (v závislosti na error_reporting a display_errors apod.) následující:

--- <br /> <b>Warning</b>: htmlspecialchars() expects parameter 1 to be string, array given in <b>...\array.php</b> on line <b>7</b><br /> --- Arrayb --- <br /> <b>Notice</b>: Array to string conversion in <b>...\array.php</b> on line <b>11</b><br /> Array

Tedy dopadlo to takto:

To neměl být kompletní výčet reakcí různých funkcí, jen jsme si tím ukázali, že různé funkce (a operátory) se mnohdy mohou chovat jinak (a to zvláště v php), což způsobuje těžko předvídatelné chování. Samozřejmě, že to lze předvídat, ale podle mého názoru je daleko jednodušší kontrolovat typ.

Odhalení implementace v PHP pomocí pole na vstupu není obvykle tak závažné jako u ASP.NET, což lze odhadnout z obou výstupů. Ale zapomenout na něj nemůžeme, z chybových hlášek lze i tak něco vyčíst. Určitě lze vyčíst název souboru, ve kterém se to stalo. Za určitých podmínek to může být i špatně pojmenovaný db.inc.

Neodeslání hlaviček a následný XSS

Tady znám php, ostatní nevím

PHP

Výpis chyby, který jsme si popsali v části odhalení implementace, způsobí odeslání hlaviček, pokud již nebyly odeslány. Výjimku tvoří například output_buffering, který tu nebudu rozebírat. Pokud se po chybě pokusím odeslat hlavičky, obvykle to tedy nepůjde (a způsobí jen warning). Skript však pojede dál, což není moudré. Třeba chtěl poslat hlavičku content-type, location nebo něco podobného a prohlížeč kvůli tomu bude jinak chápat obsah.

U content-type může jít buď „jen“ o chybné kódování, což si moc dobře v praxi u HTML nedovedu představit, nebo o poslání úplně jiného MIME typu. Typicky při vypsání obrázku. A co se týče hlaviček location apod., možná namítnete, že by autor musel udělat takovou nechutnou věc, že by po tom ještě nechal psát výstup, který by byl ještě k tomu špatně escapovaný. Jo, s tím souhlasím, ale stát se to teoreticky může.

Parametr má jiný význam jako řetězec a jiný jako pole

Tady mě zatím nenapadá moc konkrétních možností. To ale neznamená, že to nelze zneužít i jinak, u include na přání jsem taky ze začátku jen tušil, že potenciálnímu útočníkovi umožňuji více, než je nutné. Taky jsem ze začátku neměl žádný nápad na útok a potom se jen hromadily.

Představte si funkci (metodu), která má nějaký parametr. Pokud předám řetězec, bude to něco znamenat. Ale pokud předám pole, nebude to chyba, ale bude to znamenat něco jiného. Je však možné, že se vám tam pole vůbec nehodí. Útočníkovi však může.

Tento útok sice vysvětluju na funkcích (metodách), ale jde o obecnější problém. Vyskytnout se může například i u netypového polymorfismu.

Javascript - zrádný netypový polymorfismus

Představte si, že děláte inzertní systém, kde se cena odvíjí od délky textu. Používáte přitom serverový JavaScript a použitá platforma umožňuje takto předat pole.

Uvědomte si, jak zrádně se bude chovat vlastnost length. Když ji zjišťujete u řetězce, dá vám délku řetězce a cena inzerátu se spočítá správně. A když ji zjišťujete u pole? V tom je ten háček! Pole má taky vlastnost length. Ale ta vůbec neudává délku řetězce vzniklého konverzí, ta udává počet prvků pole!

Ještě se vraťme k tomu poli - zkusme si uvědomit, jak se pole přetypovává na řetězec. Zkuste do prohlížeče zadat adresu javascript:alert(['foo']) a případně javascript:alert(['foo', 'bar']). To by se útočníkovi docela hodilo! Vrátí to čárkami oddělený seznam položek pole konvertovaných na string. A útočník má libovolně dlouhou reklamu za cenu jednoho znaku!

To by v typových jazycích jako Java vůbec nemohlo jít. Když zanedbám fakt, že v Javě se velikost řetězce zjišťuje nepatrně jinak než počet prvků v poli, je tu ještě typový problém: pole i řetězec by musely implementovat stejné rozhraní nebo dědit ze stejného předka, který by zajistil metodu (zde by asi nešlo o vlastnost) pro zjištění délky. To by však v tomto případě bylo asi dost nelogické.

Závěr

Lze jednoznačně doporučit kontrolovat vstupní datové typy z http. Je to sice asi často opomíjené, ale kontrolou se můžete vyhnout velkým i malým bezpečnostním problémům.

Bezpečnostní problémy vyplývající z vynechané kontroly může být navíc těžké odhadnout. Jednodušší než odhadovat rozsah problémů je zcela určitě tento problém řešit.

Nakonec ještě zopakuji jedno doporučení: nespoléhejte se na to, že na vstupu mohou být jen dva různé datové typy. Buďte prozíraví a nekontrolujte, zda daný typ není nevyhovující, ale zda je vyhovující. Možná vás to nebude stát dokonce ani písmenko navíc!

Diskuzi ke článku naleznete zde.

Linkování

Líbí se Vám tato stránka? Zalinkujte ji!

Chcete sledovat novinky? Pokud si právě prohlížíte článek a hledáte RSS pro celý web, pak jste trošku jinde. Možná hledáte poslední změny.

Validní HTML 4.01 StrictValidní CSS 2.0Validní hlavní RSS kanálPHP 5Apache
referer: UA:CCBot/2.0 (http://commoncrawl.org/faq/) time:0.23631100 1513497178
web
mail
comment