Přeskočit na hlavní obsah

Ukládání hesel v databázi

Přihlášení pomocí uživatelského jména a hesla je nejčastějším způsobem ověření identity uživatele. Hesla jsou kritickým prvkem aplikace a je nutné jim proto věnovat zvláštní péči. Základním pravidlem je ukládat hesla do databáze v hashované podobě.

Všechna hesla hashovat

Všechna hesla by se měla do databáze ukládat v hashované podobě. Prohnání některou hashovací funkcí vytvoří z původního hesla jeho otisk (hash). Z otisku ale již nelze zpětně spočítat původní heslo. Proto se tyto funkce také někdy nazývají jako jednocestné. Takovou funkcí je například SHA-256:

Původní heslo:
nbusr123
SHA-256 otisk:
7751e53856859­902f722f43acc6af7fd1a554­89daa9a57c6e370d­f9372988258

Vždy, když proženete řetězec „nbusr123“ funkcí SHA-256, dostanete pokaždé tentýž otisk. Zpětně ale z daného otisku původní heslo nikterak nezískáte.

Nebezpečí plaintextových hesel

Proč neukládat hesla v původní plaintextové podobě? Protože kdokoliv se dostane k databázi, získává automaticky seznam hesel všech uživatelů aplikace. Může to být například hacker, který se prolámal do filesystému. Anebo útočník tahající data z databáze skrz nějakou SQL-Injection díru. Ale ani samotnému autorizovanému vlastníkovi aplikace po původních heslech svých uživatelů nic není.

Samozřejmě, pokud se někdo dostane k vaší databázi, může si už zpravidla dělat cokoliv s celou aplikací. Bohužel nejde zdaleka jen o vaši aplikaci. Velká část uživatelů používá jedno heslo pro všechny služby. Útočník tak prolomením (často zcela zanedbatelné) aplikace najednou u uživatelů získává hesla do jejich freemailů, firemních serverů, internetového bankovnictví apod.

Uložení hesla do databáze

Před uloženímdo databáze je potřeba pouze heslo zahashovat. K tomu se výborně hodí PHP funkce hash():

$st = $db->prepare('INSERT INTO auth (username, password)
                    VALUES (?, ?)');

$st->bindValue(1, 'pepa');
$st->bindValue(2, hash('sha256', 'nbusr123'));
$st->execute();

Ověření platnosti hesla

Při přihlašování uživatele musíme porovnat zadané heslo s tím uloženým v databázi. Ale ani pro tento případ nepotřebujeme obě hesla v plaintextové podobě. Místo toho budeme porovnávat jejich hashe:

$st = $db->prepare('SELECT * FROM auth
                    WHERE username = ? AND password = ?');

$st->bindValue(1, 'pepa');
$st->bindValue(2, hash('sha256', 'nbusr123'));
$st->execute();

Komentáře

  1. hashovat hesla je absolutní minimum pro zvýšení bezpečnosti. Do mnoha aplikací se dá přihlásit pouze se znalostí hashe hesla.

    Čekám až napíšeš něco o generování klíčů pro každou uživatelskou session :)

  2. Prisla mi velmi zajimava poznamka o tom, ze uzivatele pouzivaji vzdy stejna hesla pro vice sluzeb. Nejlepsi zpusob, jak prolomit heslo uzivatele je nechat si ho od nej rict. Jako je tomu napriklad na sluzbe borec pro studenty VSE, kam se uzivatele hlasi svym xname, ktery se taktez pouziva pro prihlaseni do skolni site. Zajimalo by me, kolik lidi se uz zkouselo prihlasit do teto aplikace heslem pro pristup k siti VSE :), pak uz administratorovi borce staci si je jen precist.

  3. A ako by si asi chcel zistit ten HASH ??? Tak to by ma zaujimalo :-D

  4. [3] Jak bylo popsáno v článku, SQL Injection, :D

  5. Pokud se už někdo dostane do databáze, nejspíš mu nebude dělat problém změnit heslo tak, aby i jeho nehashovanou formu znal.

    Další problém je když běžný uživatel zapomene heslo, pak se to musí řešit přes nějaké náhradní, a to je i pro uživatele dost otravné.

  6. Diky za clanek ;-) Tohle jsem hlidal.

  7. sorry že otevíram takhle starou diskuzi, ale neni ideální uložit salt do db a pak ho vůbec nevyužít ale solit to heslem nebo uživatelskym jménem? :) to by útočníka tak zmátlo že by se na to radši vybodnul