Nikdy nevíš, kdy to přijde
Zobrazit menu   MENU

Jak ukládat uživatelská hesla v databázi?

16.9.2019, 15:03

V dnešním článku se podíváme na stále aktuální téma a to jak ukládat uživatelská hesla. Mnozí z Vás si teď patrně řeknou, že na tom již dlouho není nic k řešení a všichni určitě používají dostatečná řešení. Nicméně stále se objevující články a úniku špatně chráněných hesel a to i u velkých celosvětových služeb by nás měly vyvést z omylu.

Pokud máte jakoukoliv aplikaci, kam se uživatelé přihlašují, musíte vyřešit způsob, jak budou uložena jejich hesla v databázi. V tomto článků si projdeme několik způsobů, kterými to je možné řešit a začneme od těch nejhorších.

Heslo jako prostý text

Asi nejstarší způsob je ten, který napadne každého začátečníka - prostě uložit heslo jako řetězec. Může se to na první pohled jevit jako dobré řešení, například když uživatel heslo zapomene, můžeme mu ho zaslat. Problémy jsou tu minimálně dva, první je že hesla jsou takto čitelná pro kohokoliv kdo má k databázi přístup (externí programátor) a může tak snadno zneužít jakýkoliv účet. Větším problémem je, že každý kdo by neoprávněně získal přístup do databáze, získá přístup ke všem uživatelským účtům. Nejen k účtům ve vaší službě, ale díky tomu že lidé používají stejná hesla, může vyzkoušet stejné přihlašovací údaje v mnoha dalších službách. Ač jde o řešení nejjednodušší, rozhodně ho nikdy nepoužívejte.

Jak jako uživatel zjistíte, že služba má takto uložena vaše hesla? Například pokud využijete funkci zapomenuté/ztracené heslo a necháte si zaslat nové. Pokud vám služba zašle vaše původní heslo, je jasné že ho má uloženo v prostém textu. Naopak, pokud Vám heslo přišlo v registračním emailu, nemusí to znamenat tento způsob uložení. V takovém případě může být email odeslán stejným scriptem, který heslo ukládá a tedy v tu chvíli je ještě známé v čitelné podobě.


Hashované heslo pomocí MD5

Další možností, která se dříve velmi hojně užívala a často ji naleznete i dnes je hashování hesla pomocí funkce MD5. Hashovací funkce vytváří z libovolně dlouhého vstupu vytvoří řetězec fixní délky, v případě MD5 je to 32 znaků. Z řetězce "Moje heslo je super" tak získáme hash "53373359a13959868b9136cdead513ba". Této vlastnosti se využívá například pro kontrolu integrity souborů po jejich přenosu (musí mít stejný hash před i po). Z logiky fungování vyplývá že jakákoliv sebemenší změna ve zdrojových datech způsobí změnu i na výstupu a stejný vstup bude mít vždy stejný výstup. Více různých vstupů může mít sice stejný výstup, ale pravděpodobnost je tak malinká, že ji můžeme ignorovat.

Snadno tedy můžeme heslo před uložením do databáze prohnat touto funkcí a vzniklý řetězec uložit. Při přihlášení pak zadané heslo opět zahashujeme a porovnáme vůči sobě pouze hashe hesel. Nemáme tedy uložené heslo v čitelné podobě, žádný programátor ho v databázi nevidí a při úniku dat útočník také hesla nezíská. To zní docela dobře ne?

Bohužel situace s MD5 není tak ideální jak by se z předchozího mohlo zdát. V roce 2004 byly nalezeny velké bezpečnostní chyby u MD5. Větším problém se pak stalo vytváření tzv. rainbow tables. Jde o "předpočítané" tabulky hesel čítající miliony záznamů pro nejčastější slovníková hesla. Pokud tedy máte hash hesla, můžete ho zkusit vyhledat v této databázi a pokud jde o slabší heslo, máte dobrou šanci že získáte i hodnotu před použitím MD5.

Když přišly rainbow tables, přišlo i řešení jak bezpečnost MD5 zvýšit. Jde o tzv. přidání soli k heslu. Tímto osolením je myšleno přidáním nějakého rětězce k heslu předtím, než je použita hashovací funkce. Ideální je, pokud je pro každého uživatele přidávaný řetězec jiný, třeba jméno, nebo email, aby hashe dvou různých uživatelů se stejným heslem byly různé. Abychom řešení ještě vylepšili, můžeme sůl přidat opakovaně a hashovací funkci zanořovat. Pokud na hashování použime něco jako MD5(MD5(heslo + "adsaw") + MD5(MD5(heslo + "ae2" + email))), můžeme s poměrně velkou jistotou říci že jakékoliv předpočítané tabulky budou k ničemu.

Mnoho současných aplikací tento způsob uložení hesla používá, často z historických důvodu, protože přechod na nový způsob úkládání může být v běžící aplikace poměrně náročný. Pokud však vytváříte aplikaci novou, která není limitována historií, určitě využijte jiný způsob ukládání hesel než pomocí hashe MD5.


BCRYPT

BCRYT je hashovací algoritmus, pokud se budeme bavit o PHP, znamená to pro nás použití funkce password_hash(). U té můžeme pomocí parametru zvolit i algoritmus jiný, ale BCRYPT je výchozí a nejpoužívanější.

Čím se liší od MD5? Automaticky používá náhodnou sůl a kvalitnější algoritmus pro hashovaní. Neplatí také pravidla uváděná výše. Pro stejný vstup po použití funkce password_hash nedostaneme vždy stejný výstup. Pokud tedy dva uživatelé mají stejné heslo, z uloženého hashe to není poznat. Výstupem je řetězec dlouhý 60 znaků, který začíná znakem $ a má 3 části. První určujte typ použitého algoritmu, druhá salt a třetí samotný hash. Výsledek vypadá nějak takto:

$2y$10$.vGA1O9wmRjrwAVXD98HNOgsNpDczlqm3Jq7KnEd1rVAGv3Fykk1a


Jak tedy ale porovnat zadané heslo, pokud i při stejném vstupu je výsledek jiný? K porovnání nemůžeme použít klasicky operátor rovnosti, ale opět speciální funkci, v případě PHP jde o password_verify().

Další výhodou tohoto řešení je jeho pomalost. Nemělo by to být naopak? Ne skutečně je pomalost výhodou. Pomocí md5 vygenerujeme na běžném počítači tisíce hashů během jediné sekundy. BCRYPTu trvá hashování řádově 100ms, díky tomu není tak snadné snažit se rozlousknout hesla silou. Pokud tedy stavíte novou aplikaci, kde musí být uložena uživatelská hesla, tento způsob je jednoznačně ten, který byste měli zvolit.


Co dělat při úniku hesel?

Snad nikdo by si takovou situaci nepřál, to ale neznamená že bychom na ni neměli být připraveni. Průnik do databází a únik uživatelských údajů se stává i těm největším společnostem na světě. Často se stávalo že informace byly zamlčovány. Tomu by nyní měl být konec, alespoň dle evropské legislativy, která nařizuje o úniku osobních údajů informovat úřady podle přesně předepsaného postupu. Vzhledem k tomu že jsme součástí EU, rozhodně bychom tento krok neměli ignorovat.

A co dále? určitě bychom se měli zaměřit na to, jak k průniku do databáze vůbec došlo a znemožnit stejný útok v budoucnu. Celkově bychom únik neměli utajovat, ale měli bychom o něm naše uživatele informovat. Co se týče uniklých hesel, jsou dvě možnosti jak postupovat. Radikálnější je všem uživatelům hesla vyresetovat a nahradit vygenerovanými, které jim zašleme společně s informací o úniku. Druhou možností je pak pouze ve zprávě doporučit změnu hesla. To můžeme udělat v případě kdy víme, že k úniku došlo ale hesla byla dostatečně zabezpečena.


Štítky: #sifrovani   #databaze   #hesla   #bezpecnost