Autorizace uživatelů v PHP

    1

    Programujete-li web a chcete, aby se uživatelé přihlašovali pod svým jménem a heslem, potřebujete při vstupu na stránky (kromě úvodní logovací) mít jistotu, že skutečně přistupuje ten uživatel, za kterého se vydává.

    Způsobů, jak toho docílit je hned několik. Předávat heslo v adrese samozřejmě nelze, stejně jako nelze předávat pouze samostatné ID uživatele (kdokoli by si mohl zadat cizí ID, a tak se podívat na cizí účet). Já zde popisuji jeden ze způsobů, který lze použít již v PHP3. Jedná se o řešení předáváním zahashované kombinace uživatelského hesla a náhodného klíče.

    Ochrana přístupu

    Ochrana přístupu uživatele je v popisovaném řešení zajištěna třemi základními vlastnostmi:

    • není předáváno jméno ani heslo uživatele
    • předávaný autorizační klíč je dostatečně dlouhý, aby se nedal zapamatovat pohledem
    • autorizační klíč se mění při každém přechodu ze stránky na stránku, tedy v momentě jeho zobrazení v poli adresy je již neplatný

    Nyní se podívejme, jak se těchto vlastností dosáhne.

    Princip řešení

    Při přihlášení a úspěšné autorizaci uživatele pomocí jména a hesla na úvodní stránce je vygenerován náhodný klíč (nemusí být nijak dlouhý). Tento klíč se uloží do databáze uživatele (stačí klasický sloupec typu INT – v MySQL). Následně je kombinace hesla a vygenerovaného klíče zahashována do dlouhého těžko zapamatovatelného řetězce – kódu, který se předává následujícím stránkám v adrese jako proměnná.

    Při vstupu na další stránku se z databáze přečte heslo a kód odpovídající uživateli s daným ID. Pomocí stejné hashovací funkce se zjistí správný kód a ten se porovná s kódem předaným v adrese. Jestliže jsou stejné, je uživatel kladně ověřen. Dále se vygeneruje nový náhodný klíč, opět uloží do databáze a znovu zahashuje s heslem.

    Zahashování znamená jednoznačné zakódování na číslo, popř. řetězec pomocí nějaké funkce. Přitom se předpokládá, že dobrá hashovací funkce bude přiřazovat výsledky rovnoměrně do oboru hodnot, i když vstupní hodnoty rovnoměrně zadávány nebudou. Tedy i pro velmi podobné vstupy funkce vrátí velmi nepodobné hodnoty.

    Implementace řešení

    Pro implementaci tohoto zabezpečení jsem použil databázi MySQL a předpokládám, že mám tabulku UZIVATELE se sloupci ID, KLIC typu INT.

    Jako hashovací funkci jsem použil funkci md5, která je standardní součástí PHP (oddíl Strings). Tato funkce kóduje (hashuje) řetězec na řetězec na základě algoritmu Message-Digest. Ke spojení hesla a kódu je použita klasická konkatenace (spojení) řetězců. Ukázka činnosti funkce md5 je zde:

    md5(„heslo“) = „955db0b81ef1989b4a4dfeae8061a9a6“
    md5(„veslo“) = „4bf643bf3816722ac9cbed5b6bb6c3c6“
    md5(„veslo2“) = „db70577ce6a3772f22170f2a6cd8d171“

    Takto vypadá funkce, která vygeneruje klíč, uloží jej do databáze a vrátí kód:

    function novy_kod($id) {
       // Vygenerování klíče
       $klic = rand(0,9999);
       // Uložení klíče
       mysql_query(„UPDATE UZIVATELE SET KLIC=\“$klic\“ WHERE ID=\“$id\“;“);
       // Vygenerování kódu
       list($heslo) = mysql_fetch_row( mysql_query(„SELECT HESLO FROM UZIVATELE WHERE ID=\“$id\“;“) );
       $kod = md5($heslo.$klic);
       return $kod;
    }

    Následující funkce provádí autorizaci uživatele a vrací úspěšnost:

    function Autorizace($kod, $id) {
       // Načtení hesla a klíče z databáze
       list($db_heslo, $db_klic) = mysql_fetch_row( mysql_query(„SELECT HESLO, KLIC FROM UZIVATELE WHERE ID=\“$id\“;“) );
       // Vygenerování kódu
       $spravny_kod = md5($db_heslo.$db_klic);
       // Test správnosti kódu
       return ($spravny_kod == $kod);
    }

    Na svých stránkách pak už jen voláte funkci Autorizace a v případě úspěchu vygenerujte nový klíč. Ukázka stránky pak může vypadat následovně:

    <?
    if (!Autorizace($kod, $id)) {
       Header(„Location: chyba.php“);
       exit;
       }
    $kod = novy_kod($id);
    ?>
    <a href=“jinastranka.php?id=<?echo $id?>&kod=<?echo $kod?>“>Jiná stránka</a>

    Tyto ukázky jsou pouze ilustrační a chybí v nich ošetření databázových chyb.

    Uvědomte si, že heslo není nikde posíláno mezi serverem a klientem (samozřejmě kromě úvodního zalogování) a veškerá práce s ním neopustí server. Přesto je vždy ověřeno, že se jedná o téhož uživatele jako minule. Dále je také třeba si uvědomit, že když se uživatel pokusí přihlásit ze svou různých míst (stačí 2 okna prohlížeče na stejném počítači), první session skončí chybou.

    Jiná řešení

    Další možná řešení problému, která se v praxi používají, je uchováváni IP adresy, ze které se uživatel přihlásí, a její expirace po jisté době nečinnosti (např. 30 min). V PHP4 máte navíc možnost použít tzv. sessions, které umožňují uchovávat hodnoty proměnných v průběhu několika HTTP volání (request) aniž by byly předávány v adrese stránky.

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

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

    1 Příspěvěk v diskuzi

    Odpovědět