Register globals a jejich bezpečnostní rizika
Vzhledem k důležitosti tohoto článku jsem se ho rozhodl exhumovat ze starého blogu a znovu vydat
Protože se poměrně často v PHP projektech setkávám s chybami, respektive bugy, způsobené nastavením na webovém serveru register_globals = on, tak bych tento “článek” rád věnoval této problematice.
Co to jsou register globals ?
Register globals je nastavení na webovém serveru, které způsobuje že jsou prvky v poli globálních proměnných (často $_GET, $_POST, $_SESSION …) přístupné také pod proměnnou s názvem stejným jako prvek v globální proměnné.
Příklad by to měl vysvětlit:
Představte si, že volám stránku s parametry index.php?bla=test
1 2 3 4 5 6 7 8 | <?php //register globals = on echo $_GET['bla']; //vypíše "test" echo $bla; //vypíše "test" //register globals = off echo $_GET['bla']; //vypíše "test" echo $bla; //nevypíše nic, protože proměnná $bla je prázdná ?> |
Jaký problém spočívá v register globals ?
Můžete si říct, že v příkladu nahoře to vypadá pěkně a výsledkem je zjednodušení kódu, ovšem opak je pravdou. Ukáži vám to na pár příkladech:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <?php/ /ověření autorizace fiktivního uživatele if($uzivatel == "admin") { $authorized = true; } //kontrola jestli se promenna $authorized == TRUE if($authorized) { udelejNeco(); udelejDalsiVecJenomProAutorizovane(); } ?> |
Dobře, to je sice hezké, ale co se stane, když zavolám aplikaci s parametrem stranka.php?authorized=true a budu mit zaple register globals ? Proměnná $authorized bude nastavena na true bez ohledu na to jestli je dotyčný admin nebo ne!
Další příklad:
Nejdříve si potřebujeme objasnit, jak PHP zachází se řetězci ….
1 2 3 4 5 6 7 8 9 | <?php $string = "test"; echo $string[0]; //vypíše první znak v proměnné $string ... tedy "t" echo $string[2]; //vypíše třetí znak v proměnné $string ... tedy "s" //a co se stane když použijeme nečíselný index ? //PHP jej vyhodnotí jako index 0 ! echo $string['backora']; //vypíše první znak v proměnné $string ... tedy "t" ?> |
Jasné ?
1 2 3 4 5 6 7 8 | <?php $auth['nick'] = "nick"; $auth['password'] = "heslo"; if ($_GET['pass'] == $auth['password'] && $_GET['nick'] == $auth['nick']) { udelejNecoJakoAdmin(); } ?> |
Tento příklad vypadá bezpečně, ale ve skutečnosti bezpečný není.
Představte si, že zavolám tuto stránku page2.php?auth=backora …. co myslíte že se stane ?
PHP nastaví proměnnou $auth jako řetězec “backora”, poté nastaví první písmeno proměnné $auth na “n” (první písmeno řetězce “nick”), na dalším řádku nastaví první písmeno proměnné $auth na “h” (první písmeno řetězce “heslo”) … a nakonec ověří jestli se první znak v $auth (nyní je $auth rovno “hackora” rovná $_GET['pass'] a poté jestli se rovná $_GET['nick']. Jestliže ověření vrátí true, proběhne kód v chráněné části.
Takže nám stačí zavolat stránku jako page2.php?auth=backora&nick=h&pass=h a máme povolení admina !
Jak tyto problémy vyřešit ?
Odpovědi jsou dvě a obě stejně jednoduché
- Nastavit register_globals == off (na většitě hostingů nemožné)
- Inicializovat proměnné
To znamená nastavovat proměnným defaultní hodnoty … ukážu vám jak by se daly opravit předchozí příklady
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <?php $authorized = false; //ověření autorizace fiktivního uživatele if($uzivatel == "admin") { $authorized = true; } //kontrola jestli se promenna $authorized == TRUE if($authorized) { udelejNeco(); udelejDalsiVecJenomProAutorizovane(); } ?> |
1 2 3 4 5 6 7 8 9 | <?php $auth = array(); $auth['nick'] = "nick"; $auth['password'] = "heslo"; if ($_GET['pass'] == $auth['password'] && $_GET['nick'] == $auth['nick']) { udelejNecoJakoAdmin(); } ?> |
Nechce se mi hledat neinicializované proměnné, jde to usnadnit ?
Ovšem že jde, nastavte si stroj PHP tak, aby zobrazoval i E_NOTICE chyby (malé bezvýznamné chyby, jako například použití neinicializované proměnné). Ale pozor, při zapnutní E_NOTICE dochází i k ověřování jestli existuje polek prve, kdyz se k nemu pokusíte přistoupit, což je v některých případech mírně otravné.
Ale doporučuji si zobrazení E_NOTICE pro vývoj aplikace zapnout a až bude aplikace hotová, tak vypnout.
Zobrazování E_NOTICE zapnete :
<?php error_reporting(E_ALL); ?>
Tags: bezpečnost, PHP, register globals