Vytvoření zaheashovaného hesla a ošetření solí

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
Manny7
Člen | 67
+
0
-

Mám z tutoriálu z oficiální stránky Nette použitu autentizaci za pomocí ověření hesla s využitím soli.
Příprava hesla k ověření vypadá nějak takto:

hash_hmac('sha256', $credentials[self::PASSWORD] . $row->salt, $config->hmacKey);

kde
$credentials[self::PASSWORD] . $row->salt je zadané heslo uživatelem při ověřovacím procesu spojené se solí, která je uložena v databázi.
$config->hmacKey je bezpečnostní klíč (zb1g7IHt1I) uložený v config.ini

Já se snažím udělat registraci využívající tento způsob přihlašování, ale trochu bádám, jak to je s tou solí a klíčem… Dočetl jsem se, že při vytváření účtu bych si měl asi vygenerovat nějaký náhodný řetězec o předem stanovené délce, tento řetězec pak uložit do DB spolu s heslem, které uživatel zadá (a to už zakóduji – třeba pomocí MD5tky nebo SHA1). Je to tak?

Jakou roli tam ale hraje pak ten hmacKey? Ten se využívá pak jen při přihlášení a porovnávání údajů? To by pak ale nemělo moc smysl, ne? …nějak nevím jak do toho algoritmu ten hmacKey aplikovat

LuKo
Člen | 116
+
0
-

Takto vytvořené heslo je následně ověřeno proti hodnotě z databáze:

<?php
$login = $credentials[self::USERNAME];
$row = \UserModel::getByEmail($login);

$config = Environment::getConfig('security');
$password =  hash_hmac('sha256', $credentials[self::PASSWORD] . $row->salt , $config->hmacKey);

if ($row->password !== $password) {
    throw new AuthenticationException("Zadali jste nesprávné heslo!", self::INVALID_CREDENTIAL);
}
?>

Z toho tedy vyplývá, že heslo je v databázi uloženo po projití výše zmíněnou funkcí hash_hmac a $config->hmacKey potřebuješ i při registraci.

Editoval LuKo (23. 8. 2010 16:22)

Blizzy
Člen | 149
+
0
-

Já tomu rozumím tak, že ten HMAC klíč je (v tomto případě) k posílení hashovací funkce. Také pokud má každá aplikace jiný HMAC klíč, vygeneruje jiný hash i při stejném vstupu a stejné dynamické soli. Sůl generovaná pro uživatele se hodí pro znemožnění použití rainbow tables (v případě znalosti HMAC klíče) a odhalení stejných hesel v případě získání hashů z databáze.

Zatímco HMAC klíč je vždy stejný (v tomto příkladu má roli statické soli), salt má každý uživatel vygenerovaný jen pro sebe (je to dynamická sůl) a uložený v databázi pro pozdější ověřování.

Je potřeba stejným způsobem hashovat heslo při vytváření uživatele jako při ověřování uživatelského hesla.

Editoval Blizzy (23. 8. 2010 16:58)

Manny7
Člen | 67
+
0
-

LuKo, Blizzy: jop.. takhle nějak jsem to nakonec dal dohromady. Ke generování soli zatím používám mt_rand(), který mi nageneruje stanovený počet číslic (10)… Ale to asi úplně ideální není… Asi by bylo lepší vytvořit nějakou množinu prvků (písmena malé anglické abecedy + číslice) a z této množiny tu sůl generovat. Přece jen se tím výrazně zmenší riziko dvou stejně nagenerovaných solí… nebo myslíte, že tohle je už přehnané?

Blizzy
Člen | 149
+
0
-

Manny7 napsal(a):

LuKo, Blizzy: jop.. takhle nějak jsem to nakonec dal dohromady. Ke generování soli zatím používám mt_rand(), který mi nageneruje stanovený počet číslic (10)… Ale to asi úplně ideální není… Asi by bylo lepší vytvořit nějakou množinu prvků (písmena malé anglické abecedy + číslice) a z této množiny tu sůl generovat. Přece jen se tím výrazně zmenší riziko dvou stejně nagenerovaných solí… nebo myslíte, že tohle je už přehnané?

Ona ta entropie v náhodných číslech je dost veliká, proto bych se toho nebál.

Pokud se bojíš, tak:

  • Můžeš přidat jako ingredience pro sůl nejen náhodné číslo, ale i třeba uživatelské jméno nebo budoucí id, pokud ho znáš.
  • Můžeš ověřit, že sůl neexistuje, a vygenerovat jinou. Např. nastavíš UNIQUE klíč pro sloupec se solí a databáze ti to zajistí sama.

Pro pevnou délku soli používej hashovací funkci.

Editoval Blizzy (23. 8. 2010 17:08)

toka
Člen | 253
+
0
-

Myslíš takto:

function salt($length = 10) {
	$i = 0;
	$salt  = '';
	$chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
	       . 'abcdefghijklmnopqrstuvwxyz'
	       . '0123456789';
	while($i++ < $length) $salt .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);

	return $salt;
}
Panda
Člen | 569
+
0
-

Co použít base_convert?

base_convert(sha1(uniqid(mt_rand(), TRUE)), 16, 36);

Jinak tyto (tzn. rand, mt_rand, uniqid) generátory jsou kryptograficky slabé, Jordi Boggiano to docela dobře popisuje v článku Unpredictable hashes for humans. Pro běžné použití ale v pohodě stačí.

toka
Člen | 253
+
0
-

Díky za poučení a odkaz na článek. Rád se dozvím něco nového.

Patrik Votoček
Člen | 2221
+
0
-

Já používám způsob okoukaný myslím z djanga https://github.com/…ies/User.php#L91