Solení hesel aneb Sůl nad zlato
Pokud máte hesla v aplikaci uložená v hashované podobě, útočník, který se dostane do databáze, nevidí jejich původní plaintextové verze. Může ale použít několik metod, jak toto opatření oslabit. Bezpečnost uložených hesel se pro takové případy dá zvýšit takzvaným solením.
Pokud se útočník dostane k hashovaným heslům, může se pokusit z daných otisků získat původní hesla. To jde pouze útokem hrubou silou, kdy se generuje systematicky jedno možné heslo za druhým, z každého se spočítá hash a porovnává s lámaným otiskem. Takový postup je samozřejmě výpočetně a časově náročný. Existuje proto několik způsobů, jak rozlomení hesla uspíšit.
Duhové nebezpečí
Prvním je slovníkový útok, kdy se předpokládá, že původní heslo je postaveno z nějakých existujících slov běžného jazyka, případně jen na konci doplněných o číslice apod. Množství nutných výpočtů a porovnání se proto rapidně snižuje.
Další možností je použítí rainbow tables. Jedná se o předem předpočítané tabulky dvojic „heslo – otisk“. Pro zkoumaný hash pak v tabulkách pouze stačí najít odpovídající původní heslo. Takové rozlomení je relativně rychlé. Rainbow tables jsou ale náročné na úložný prostor, proto se zpravidla opět počítají jen z omezené skupiny hesel, například slovníkových.
Posledním nebezpečím u jednoduše hashovaných hesel je skutečnost, že všichni uživatelé se stejným heslem mají i stejný hash. Pokud se tedy útočníkovi podaří určit z nějakého otisku původní heslo, získává automaticky přístupy všech dalších uživatelů s týmž heslem.
Osol sobě hesla svá
Některé z uvedených problému řeší solení hesel. Při hashování hesla se na vstup navíc ještě přidává nějaký další řetězec, takzvaná sůl. Sůl je pokaždé jiná, výsledný hash je tak i pro stená hesla pokaždé jiný.
Solí může být obecně cokoliv. Není nutné, aby byla tajná. Naopak, obvykle jde o veřejnou hodnotu. Jediný rozumný požadavek je, aby se lišila navzájem mezi jednotlivými uživateli.
Častým řešením bývá náhodně generovaná sůl. Tu je pak potřeba v databázi ukládat do speciálního sloupce vedle uživatelského jména a výsledného otisku. Funkce crypt() v PHP si (v závislosti na použitém algoritmu) dokonce n-znakovou sůl uchovává přímo v rámci výsledného otisku jako jeho prvních n znaků.
Nevýhody náhodné soli jsou spíše praktického charakteru, například je pak složitější realizovat Challenge/Response autentizaci, protože se sůl musí pokaždé posílat uživateli společně s výzvou.
Výrazně praktičtější mi proto osobně přijde jako sůl použít samotné uživatelské jméno. Nemusí se pro ni definovat samostatný databázový sloupec. Nemusí se nikam posílat, protože uživatelské jméno je vždy rovnou k dispozici.
Implementace solení v PHP:
Nejjednodušší možností je prosté zřetězení hesla a soli:
$hash = hash('sha256', $password . $salt);
Často se k solení používají HMAC funkce. V PHP je pro tento účel k dispozici funkce hash_hmac():
$hash = hash_hmac('sha256', $password, $salt);
HMAC sice primárně slouží k něčemu úplně jinému, tedy pro spočítání hashového autentizačního kódu zprávy, a použitím veřejně známé soli tento původní záměr zcela padá. Nicméně se dá pro solení bez problémů zneužít a dokonce je silnější (a také dvakrát složitější), než jednoduchá hash funkce se zřetězenou solí uvedená výše.
Na hrubou sílu je sůl krátká
V čem tedy konkrétně solení pomůže?
Osolená hesla jsou odolnější proti útokům s předgenerovanými tabulkami. Záleží na rozsahu a úplnosti rainbow tables, ale ve většině případů by si musel útočník pro každou sůl vygenerovat pokaždé novou tabulku příslušných hashů, což se rovná útoku hrubou silou.
Sůl také eliminuje zmíněný případ, kdy po prolomení jednoho hesla získávám seznam všech uživatelů, kteří toto heslo používají – zde to neplatí, protože každý z těchto uživatelů má nyní jiný hash.
Solení samozřejmě nezabrání klasickému útoku hrubou silou v reálném čase, a to ani při nápomocném použití slovníků nejčastějších hesel. Proti tomu ale existují jiné metody obrany, které zase zvyšují střední dobu nutnou pro úspěšný brute force. Jedná se zejména o požadavky na minimální délku a sílu zadávaných hesel.
Při čtení článku mě napadlo, k čemu to solení hesel vlastně je. Když se mi nějaký nekalý živel dostane tak hluboko do databáze, že vidí otisky hesel uživatelů, je už všechno jedno, protože to už (o moc) horší být nemůže. A že z osoleného otisku nezjistí původní heslo? Tak si tam dá otisk vlastní (možností solení není zas tak moc) a je to. A když bude puntičkář, tak tam na závěr vrátí ten původní otisk a nikdo nic na první pohled nepozoná.
Tím nechci říct, že solení je k ničemu. Jenom si myslím, že solit otisky hesel v databázi je spíš pro dobrý pocit, jinak to bezpečnost nijak zvlášť nezvyšuje.
[1] no pokud já jako útočník někde získám nějaké zahashované heslo tak musím zjistit algoritmus jakým je to hashované a z toho hashe potom původní heslo…pokud k tomu přidám sůl tak musím znát ještě tu sůl a k tomu způsob jakým je heslo osoleno takže je to podle mě určitě bezpečnější
Já přesně nevim, jak hackeřina většinou funguje ale napadá mě toto. Pokud se útočník dostane do databáze není to vetšinou i s tím, že už má přístup i na filesystém a může si přečíst sůl v php? Nevím, ptám se.
P.S. nejlepší metoda pro rozlousknutí jednoduchých zahashovaných hesel je google :-)
[1] sůl je důležitá také proto, že ukradená hashe hesel u jedné serveru nepůjdou použít pro autentizaci k jiné službě (za předpokladu, že uživatel má stejná hesla) – protože u dost služeb stačí znát pro přihlášení hash hesla.
Taky se přidám se svojí troškou do mlýna: hesla je potřeba chránit nejen v naší DB, ale i při přenosu po síti. K tomu můžeme použít metodu výzva-odpověď, kterou jsem popsal tady href=„http://frantovo.cz/blog/?q=overovani-uzivatelu-na-webu“ rel=„nofollow ugc“>http://frantovo.cz/blog/?q=overovani-uzivatelu-na-webu (třeba pokud nemůžeme použít TLS nebo mu nevěříme). Je tam i ukázková implementace pod licencí GPL.
No pěkná záležitost… na bezpečnosti ale asi příliš nepřidá. Ja používám několikanásobné zahashování (většinou pětinásobné, ale teď jsem vymyslel počítat počet zahashování z uživatelského jména), myslím že to také není špatný způsob ochrany, ale je to jak solení – bezpečnost to zas tolik nezvýší
[1][3][6] Solení hesel zvyšuje bezpečnost v těch ohledech, které jsou uvedeny v článku. Tedy zejména jako ochrana před reverzním převodem otisku na původní heslo pomocí rainbow tables či jiného již prolomeného hesla. Nejde přitom již o ochranu naší aplikace, ale o ochranu účtů našich uživatelů na jiných webech, pokud na nich používají stejné heslo. Blíže viz http://www.phpguru.cz/clanky/hashovani-hesel
[6] Prosté vícenásobné prohnání hashovací funkcí sílu otisku zpravidla nezvyšuje, je to tedy zbytečné. Navíc stávající hashovací funkce (například má oblíbená SHA-256) mají samy o sobě zcela dostačující vlastnosti, takže není potřeba se snažit jejich sílu nějak zvyšovat.
[7] Vícenásobné hashování nepovažuju moc za smysluplné. Stačí jednou a pořádně tzn. zahrnout do hashe heslo, jméno uživatele a sůl serveru + použít kvalitní hashovací funkci.
„Jediné co je mě štve je, že ikdyž to použiji v Open-Source projektu…“
Sůl tam přece dáš jako parametr, který může být pro každou instalaci toho SW jiný, resp. měl by být jiný. A pokud jde o algoritmus (co do hashe dáš, v jakém pořadí, kolikrát…), tak ten by se utajovat neměl. Jinak je to obyčejná „security through obscurity“
[1] Ale může se objevit chyba v zabezpečení, kdy šikovný útočník nechá přímo tvoje scripty vypsat obsah databáze. Takový normální MD5 hash admin účtu by mu určitě udělal radost.
A jeslti jsem to dobře pochopil, přidáváte sůl přeh hashováním. Už někoho napadlo přidávat sůl navíc i po hashování? Aneb přibližný recept na pěkně paranoidní slané tyčky:
Udělá se hash hesla trochu osoleného např. třemi vybranými znaky z mailu, vloženými mezi znaky samotného hesla na určená místa. Pak se roztříhá na skupiny znaků a proloží se taktéž rozstříhanými hashi mailu, jména, klidně třeba jenom jejich vybraných částí výcenásobně zahashovaných. A ani velikost a pořadí jednotlivých ústřižků hashů nemusí být konstantní, může se počítat z nějakých vlastností mailu nebo jména. Výsledkem může být 120 znaků dlouhý hash, vněmž je hash osoleného hesla rozmístěn na pozicích pro každého uživatele unikátních.
Nikdo bez implementace kódovacího algoritmu na takto schované heslo nepřijde – nebude vědět kde ten konkrétní hash hledat. Z vícenásobného hashování nebo jednoduchého solení je možné přijít z hashe na algoritmus který ho vytvořil a získat tak ostatní hesla či třeba s přístupem do databáze si vložit svůj hash k admin účtu, u tohohle řešení je to prakticky nemožné. Jedině získáním algoritmu z PHP scriptů nebo odchycením hesla před přijetím serverem je to možné obejít – jako i každé jiné řešení.
Složité? Ale nejjistější z nabízených variant :o)
Pro použití na normálním webu ale imho zbytečně paranoidní.
[9] Systém bys měl navrhnout vždy tak, aby byl bezpečný i za předpokladu, že algoritmus je veřejně známý. To je takové doporučení od jednoho chytrého pána