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é :)

  1. Nastavit register_globals == off (na většitě hostingů nemožné)
  2. 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: , ,

Leave a Reply