Jak weby (snad) ukládají naše hesla, aby neunikla na veřejnosti i při úniku dat

Když se registrujeme k nějaké online službě, ať je to e-mailová schránka, e-shop nebo třeba fórum, obvykle si při registraci musíme zvolit nějaké heslo, pomocí kterého se následně přihlašujeme. Mohli bychom si říci, že administrátoři daného webu se pak prostě mohou podívat do své databáze a ihned vidět, jaké jsme si zvolili heslo. Naštěstí existují metody, jak tomuto předejít, aby ani majitelé webů a databází heslo neznali, ale jde vždy o důvěryhodnost daného webu.
Jak by tedy měla služba ukládat kombinaci našeho přihlašovacího jména a hesla, aby vše bylo pokud možno co nejvíce zabezpečeno?
📝Obsah
Proč online služby neukládají hesla v původním tvaru
Uložit heslo v původním tvaru se zdá jako nejsnazší možnost. Pokud si nějaký web se zabezpečením nedělá hlavu, tak to dokonce i přesně takto dělá. Trocha práce navíc je ale i v zájmu webů, které přijímají registrace. Při úniku dat, který se prostě může stát, by mohl daný web mít zásadní problémy, protože nedokázal data dostatečně zabezpečit a zašifrovat.
Jak by tedy mělo správné zabezpečení alespoň v principu vypadat? Je pravda, že si toto nemůžeme vždy ověřit, ale můžeme spát s trochu klidnějším vědomím toho, že se naše hesla (alespoň obvykle) nepovalují na webech v původním tvaru (někdy se tomuto nezašifrovanému tvaru říká plain text).
Hesla se uchovávají v zašifrovaném tvaru
Nejdříve začněme trochu zeširoka. Základem šifrování hesel za účelem jejich uchování je takzvaná hashovací funkce. Ta funguje jednoduše tak, že zadáme nějaký vstup (tedy třeba zadané heslo, ale principielně může jít o jakýkoliv text), pomocí matematického vzorce se tato data zašifrují a my dostaneme nějaký výstup, který se naprosto nijak nepodobá původnímu tvaru hesla a v praxi jde o na první pohled zcela náhodný chumel znaků, kterému říkáme hash (čti haš).
- Příklad vytvoření jednoduchého hashe: Jako vstup naší hashovací funkce musí být prvočíslo a náš matematický vzorec je, že toto prvočíslo odmocníme a vezmeme 5. až 10. desetinné místo, které navíc ještě napíšeme pozpátku. Pokud si vezmeme kalkulačku a spočteme si odmocninu z prvočísla 3, tak dostaneme výsledek 1.7320508075… Pokud bychom vzali 5. až 10. desetinné číslo (zvýrazněno ve výsledku), tak dostaneme 508075, a podle naší vymyšlené funkce ho ještě převrátíme, takže získáme 570805, což je náš výsledný hash.
Princip je takový, že hashovací funkce by měla vypadat tak, že je poměrně velmi snadné převést vstup na výstup, ale (ideálně) nemožné odvodit z výsledného výstupu, jaký byl původní vstup. Kdybychom znali pouze výstup 815780, tak bychom dost složitě přicházeli na to, že původně zadané prvočíslo bylo 9973. Sice přesně víme, jak hash odvodit, tak přijít na původní prvočíslo v praxi znamená, že musíme prostě zkoušet a zkoušet, než na výsledek přijdeme.
S výpočetním výkonem dnešních počítačů by to byla otázka chviličky, ale jde nám spíše o princip fungování. Matematické funkce, které proměňují vstupní heslo na hash jsou výrazně komplikovanější a jsou schopny zvládat libovolný vstup, tedy ne jen prvočísla, jako tomu bylo v příkladu. Různé hashovací metody a jak výsledné hashe vypadají, si můžete vyzkoušet třeba tady. Důležitá podmínka hashe je i jeho nepředvídatelnost. Změna jediného znaku ve vstupu by měla vytvořit naprosto jinak vypadající výstup.
K čemu to všechno bylo?
Teď jsme si ukázali, jak alespoň principiálně zašifrovat nějaký text na hash. Při uchovávání hesel je toto naprosto klíčové. Pokud si totiž někde založíme účet s heslem, tak se toto heslo zašifruje do tvaru, ze kterého je nemožné získat původní heslo.
Vždy, když se poté přihlašujeme, tak se námi zadané heslo zašifruje identickou matematickou formulkou a porovná se se zašifrovanou verzí uloženou v databázi. Pokud se došlo ke stejnému výsledku, tedy je heslo stejné, jako bylo zadané při registraci, tak je přihlášení úspěšné.
Výsledné heslo se tak nikdy nemusí uchovávat v databázi v původním tvaru. Stačí znát výsledný hash a funkci, pomocí které se k tomuto výsledku došlo. I při znalosti funkce ale nelze zpětně heslo odvodit. Toto uchovávání hesel má tu výhodu, že při úniku dat zná hacker pouze výsledný hash, a ne samotné heslo. Prolomit hash by mělo být stejně náročné, jako snaha o uhádnutí hesla samotného, takže se útočníkům vlastně ani moc nevyplatí to zkoušet. Další výhoda je ta, že ani majitelé webu naše heslo neznají a ze své databáze ho nezjistí.
Hashování nemusí ochránit před slovníkovým útokem – co takhle heslo osolit?
O tom, co je slovníkový útok, jsme psali tady. Ve zkratce jde o typ útoku hrubou silou, kdy se útočník snaží přijít na naše heslo zkoušením. Slovníkový útok je ale mnohem sofistikovanější metoda, protože nezkouší hesla zcela náhodně, ale využívá znalostí a tendencí. Jako hesla tedy útočník, respektive jeho software, zkouší běžná slova, ale také informace, které zná o majiteli účtu, který chce prolomit.
Problém s hashováním je ten, že někteří uživatelé používají stejná hesla. A pokud na stejné heslo použijeme stejný způsob zahashování, tak nám vyjde i stejný hash. Pokud by se tedy útočník dostal k databázi hesel, tak může porovnat, jestli u některých uživatelů nenajde stejně zašifrovaná hesla, protože tito uživatelé používají heslo stejné. Slovníkový útok je také zákeřný v tom, že si útočník může pomocí stejné metody zahashování vytvořit tyto šifry pro nejpoužívanější hesla, takže pro něj pak není problém jen porovnat svůj seznam známých hashů s hesly, které najde v databázi. Zjednodušeně řečeno, ani hashování nezabrání útočníkovi, aby přišel na nejpoužívanější hesla.
A teď přichází na řadu další stupeň zabezpečení, kterému se říká salted hash, tedy v překladu osolený hash. Tato metoda funguje tak, že ke každému heslu se před zahashováním přidá nějaký náhodný řetězec znaků. Tento řetězec může být klidně veřejný, někdo používá jako tento řetězec třeba přihlašovací jméno uživatele. Řetězec by ale měl být rozdílný pro každého uživatele (proto použití přihlašovacího jména tak dobře funguje). Při hashování záleží i na změně jediného znaku, který vyprodukuje zcela jiný hash. Tím, že před zahashováním k heslu něco přidáme, tak je i výsledný hash zcela jiný a naprosto nepředvídatelný. I uživatelé, kteří používají identická hesla, budou mít svá hesla zašifrovaná pod jiným hashem. U legitimního přihlašování se pak akorát k heslu přidá daný salt, a až poté se ověří uložený hash.
Použití salt tak lépe chrání před slovníkovými útoky, protože pokud útočník neví, kam a dokonce ani jestli byl salt použit, tak ani nemůže snadno ověřit, jaká stejná hesla uživatelé používají. Může samozřejmě zkoušet přidávat náhodně veřejný salt ke známým heslům, ale je to pro něj hodně práce navíc. přestože nejde o vyloženě neprůstřelnou ochranu, útočník bude pravděpodobně minimálně odrazen od toho se pokoušet hesla rozklíčovat, a bude mít celkově velmi složitou úlohu na to přijít z hashe i na ta nejpoužívanější hesla.
Nikdy pořádně neznáme zabezpečení webů
Pozor ale na to, že takzvaně pod kapotu fungování webů jakožto uživatelé vlastně nikdy nevidíme. Jestli služba používá šifrování, nebo ne, se vlastně nemáme moc jak dozvědět. Druhý problém je v tom, že i šifrovací metody se časem mohou prolomit. Co dnes vypadá jako nemožné, se může jednou matematicky vyřešit tak, že je pro hackery snadné přijít na původní tvar hashe.
Jde prostě jen o další vrstvu zabezpečení účtů a našich hesel, ale ani šifrování není všespásné a vždy je možné, že i tak hesla uniknou nějakým jiným způsobem nebo že dané hashe budou časem prolomeny. Jestli tak zjistíme, že z nějaké služby, kterou používáme, unikla data, měli bychom na této službě změnit heslo i všechna hesla, která se podobají tomuto, které uniklo, i když třeba v zašifrované podobě.