21. diel - Bezpečnostné hrozby - Ako správne ukladať heslá?
V predchádzajúcej lekcii, Blog v Spring Boot - Validácia registračného formulára, sme pridali DTO pre registračný formulár a implementovali sme jeho validáciu.
V našom kurze sa dostávame k ukladaniu užívateľských hesiel, čo je potenciálna bezpečnostná hrozba. V dnešnej dobe GDPR zákonov a vysokého bezpečnostného štandardu, sa chceme v našich aplikáciách vo vlastnom záujme vyhnúť bezpečnostným chybám. Záleží nám na tom, aby ste boli naozaj dobrí. Preto naše kurzy obsahujú aj vybrané témy z kurzov Dobrých praktík a Kybernetickej bezpečnosti. Ako teda heslá bezpečne uložiť?

Heslá sa do databázy neukladajú
Pre ukladanie hesiel, a to nielen do databázy, platí jedno jednoduché pravidlo:
Žiadne heslá do databázy nikdy neukladáme !
K databáze sa môžu dostať nepovolané osoby, napr. pri hackerskom útoku na webhosting alebo našu aplikáciu. Musíme si uvedomiť, že heslá, najmä ak sú priradené k emailovým adresám, sú veľmi citlivé dáta. Veľké percento užívateľov totiž používa to isté heslo k svojej emailovej schránke aj na ďalšie služby. Útočník by teda dostal tisíce vstupeniek do emailových schránok našich užívateľov. Cez email nie je prakticky žiaden problém dostať sa kamkoľvek inam, stačí si na ktorúkoľvek službu, napr. Facebook, nechať poslať nové heslo do emailovej schránky, ktorú útočník ovláda. Aj keby u užívateľov email uložený nebol, je možné užívateľa zvyčajne jednoducho spojiť podľa mena alebo jeho príspevkov s nejakým iným účtom na internete, získať jeho emailovú adresu, následne prístup do jeho schránky a tak aj k ďalším ním využívaným službám. Toto je okrem iného dôvod, prečo emailové schránky zvyčajne vyžadujú dvojfázové overenie, avšak nie všetci ho budú mať aktívne.
Na overenie, že užívateľ zadal správne heslo, jeho heslo ale predsa mať uložené potrebujeme, však?
Hashovanie hesiel
Hashovanie [hešovanie] je jednosmerný prevod nejakých
vstupných dát na inú hodnotu. Ak zahashujeme užívateľské heslo, získame
jeho odtlačok. Ide obvykle o reťazec zdanlivo nesúvisiacich
znakov a číslic, z ktorého nie je možné zistiť jeho pôvodné
heslo. Napr. pre heslo ictDemy1 by sme dostali
nasledujúci reťazec:
$2a$10$bPEtRTvJ1A1Cu4mJwIbJM./mGB8myOGaRIcw07IQN0c2Ih32k.Ht2
Namiesto hesla užívateľa ukladáme vždy len jeho odtlačok, z ktorého nemožno pôvodné heslo získať.
Hashovacie algoritmy sú kryptograficky navrhnuté tak, že ich nemožno prelomiť inak ako skúšaním všetkých kombinácií. To je pri dobre zvolenom algoritme a soli (viď ďalej) možné v rozumnom čase vykonať len v minimálnej miere. Okrem ukladania hesiel sa hashovanie využíva tiež napr. na elektronické podpisy alebo kryptomeny.
Overenie hesla pomocou odtlačkov
Ako teraz ale zistíme, že používateľ zadal správne heslo? Je to jednoduché. Z hesla, ktoré užívateľ zadal, spočítame odtlačok. Ten porovnáme s odtlačkom, ktorý máme uložený u daného užívateľa v databáze. Pokiaľ sú odtlačky rovnaké, musel zadať aj rovnaké heslo!
Takúto autentizáciu si môžeme predstaviť, ako by si užívateľ ľahol
do piesku a my sme si odfotili jamu, ktorá po ňom zostala. Keď príde znova,
necháme ho znova ľahnúť do piesku a porovnáme, či jama po ňom vyzerá
rovnako, ako jama, ktorú máme pri jeho účte. Ak áno, ide o toho istého
človeka (ak výrazne nepribral, čo sa pri hesle nestane
). Keď nám niekto ukradne knihu s
fotografiami jám, nikdy z nej nezistí, ako vyzerajú tváre ľudí, ktorí k
nám chodia. Rovnako, keď nám niekto ukradne databázu webu s hashmi hesiel,
nikdy nezistí heslá našich užívateľov.
Títo dvaja ľudia majú v piesku rovnaké odtlačky a jedná sa tak o rovnakého človeka:
A tu sa niekto snaží vydávať za niekoho iného, odtlačky nesedia:
Hashovanie vs. šifrovanie
Hashovanie si nepletieme so šifrovaním.
Šifrovanie je obojsmerným prevodom danej hodnoty a bolo by potom možné heslo spätne získať. Heslá šifrujú napr. kľúčenky, ktoré potrebujú pôvodné heslo, aby ho mohli odoslať do nejakej ďalšej služby. My heslo nikam neposielame, iba overujeme, že používateľ zadal to isté. Preto ho nešifrujeme, ale hashujeme. Šifru je možné dešifrovať, hash nie.
Ďalšou častou chybou je, že si ľudia myslia, že hashe sú unikátne. Pravdepodobnosť je síce zanedbateľná, ale pre dve rôzne heslá môže hashovacia funkcia vygenerovať rovnaký hash. Pri overení hesla to nijako nevadí, ale hashe by sme nikdy nemali používať ako unikátne identifikátory.
Slabé stránky hashovania
Takmer každý známy web už niekedy čelil hackerskému útoku. Ako už bolo povedané, hashovacie algoritmy sú jednocestné. To môžeme chápať tak, že časť informácií z pôvodného hesla jednoducho zahadzujeme. Hackeri sú však vynaliezaví a rovnako prišli na v zásade dve metódy, ako pôvodné heslo z odtlačku predsa len získať. Stručne si ich spomenieme, aby sme vedeli, na čo si dávať pozor.
Slabá stránka 1 - Algoritmus
Hashovanie je navrhnuté tak, aby výpočet odtlačku počítača chvíľu trval. Počítače sa však stále zrýchľujú. Pokiaľ budeme používať zastarané algoritmy ako napr. md5, môžu hackeri jednoducho vyskúšať všetky možné heslá kombináciami znakov do určitej dĺžky. Z týchto hesiel potom budú počítať odtlačky, kým sa netrafia do toho, ktorý máme uložený v databáze. U moderných algoritmov nemožno na súčasných počítačoch hashe takto rýchlo počítať.
Spring Boot Security má v sebe zabudované dva algoritmy spojené s hashovaním hesiel:
- bcrypt – Moderný algoritmus za vývojárov rieši
pridávanie soli k heslu a prípadnú voľbu hashovacieho algoritmu, preto aj
tento algoritmus využijeme. Implementáciu algoritmu možno nájsť v triede
BCryptPasswordEncoder. - Argon2 – Ešte modernejšia alternatíva k bcryptu.
Implementáciu algoritmu možno nájsť v triede
Argon2PasswordEncoder.
U algoritmu možno obvykle nastaviť aj náročnosť výpočtu
(číslo 10 v ukážke hashu na začiatku lekcie). Čím väčšie
bude, tým dlhšie bude trvať odtlačok vypočítať. Nie je to však
ekvivalent bezpečnosti, príliš vysoká hodnota môže spôsobovať
výkonnostné problémy aplikácie.
Slabá stránka 2 - Neosolené heslo
Určite viete, že veľa ľudí používa heslá ako 123456 a podobne. Aj rozumnejšie zvolené heslá by sa nám však v databáze opakovali. S touto problematikou súvisí napr. birthday paradox - Aká myslíte, že je pravdepodobnosť, že majú v skupine 23 náhodne zvolených ľudí dvaja ľudia narodeniny v rovnaký deň? Je to 50 %.
Nie je teda problém podľa početnosti výskytu rovnakých odtlačkov v databáze hesla hádať. Alebo mať na najpoužívanejšie heslá predpočítané odtlačky na najznámejšie algoritmy. Takým databázam hashov sa hovorí rainbow tables. Môžeme sa jednoducho pozrieť, či niekto náhodou nemá odtlačok "73cd1b16c4fb83061ad18a0b29b9643a68d4640075a466dc9e51682f84a847f5" a hneď vieme, že jeho heslo je "superman".
Z tohto dôvodu k heslu užívateľa pred výpočtom hashu ešte vždy niečo pripojíme, napr. ID užívateľa, čím používatelia aj s najhlúpejšími heslami budú mať hashe, ktoré nebudú v dúhových tabuľkách. Hovoríme, že tým heslo prisolíme.
Soľ je zvyčajne aj u každého užívateľa iný reťazec. Pokiaľ si teda 10 našich užívateľov nastaví heslo "qwerty", použitím soli budú mať všetci iný hash, pretože sa ku "querty" pridá nejaká ďalšia hodnota. Vytrvalý hacker, čo si dá tú námahu predpočítať pár častých hesiel pre jednu našu soľ, tak nemôže výsledné hashe použiť pre ďalších užívateľov a pri každom musí začínať znova.
Moderné algoritmy si soľ generujú samy a ukladajú si ju priamo do výsledku (časť výslednej hodnoty hashovacej funkcie je odtlačok a časť soľ). Nemusíme sa teda o nič starať. Je však vhodné vždy overiť, že to zvolený algoritmus robí alebo sa očakáva, že soľ pripojíme my.
V ďalšej lekcii, Blog v Spring Boot - UserEntity a UserRepository, vytvoríme entitu pre užívateľov a repozitár so základnými CRUD operáciami.

David sa informačné technológie naučil na