Bezpečné ukládání hesel do MariaDB

password_hash návod, příklad a ukázka (password_verify)

Pro ukládání hesel do MariaDB databáze (dříve MySQL) se rozhodně nedoporučuje ukládat tato hesla v otevřeném (tedy čitelném) tvaru. Dokonce ani zašifrovaná hesla s možností dešifrování není doporučováno ukládat do databáze. Také pro čtení a zápis dat do databáze se doporučuje (hlavně jako ochrana před SQL injekcí) používat parametrizované SQL dotazy.
Proč je zde zmiňována MariaDB a ne MySQL? Je to proto, že MySQL koupila jedna velká společnost (ORACLE) a zřejmě bude z toho chtít mít zisk. Proto vznikla MariaDB a funguje velmi dobře, údajně na ní jede i GOOGLE vyhledávač.

Jak tedy hesla ukládat?

Doporučený postup je ukládat hesla jako výtah zprávy (otisk zprávy), hash (v doslovném překladu
„zmrvení zprávy“). Je to jednosměrné upravení zprávy (řetězce), které již zpětně nejde dešifrovat, Secure Hash Algorithm = SHA512, nověji ukládat hesla pomocí password_hash("moje tajne heslo", PASSWORD_DEFAULT).
Ale bezpečnost hashí se mění, dříve používané hashe MD5, SHA1 jsou již označené jako překonané a jsou bezpečnostním rizikem. Doporučuje se pro hesla již SHA512. Ale ještě lepším, bezpečnějsím a jednodušším zůsobem je použití PHP funkcí password_hash a password_verify.

Ukázka výtahu zprávy SHA512 v PHP

<?php
echo hash("sha512","moje tajne heslo");  // hash hesla
?>

Výstupem je hash hesla:

ba8dbaecd78d762799715e5fe4559428a1e4b14c68ada9f5581b868c3102243fd485ef6a3239c27bb0636f72e330325792c29ab28405dfe9b62e2678a6a0a9df

Funkce hash("sha512","moje tajne heslo") při stejném vstupu na výstupu dává vždy stejný hash!

Mohlo by se zdát, že nikdo nemůže přijít na to, jaké bylo zadáno původní heslo. Ale hackeři a podobná individua  nezahálejí, vyvinuli „duhový seznam“ předhashovaných hesel (rainbow list).

Co je duhový seznam předhashovaných hesel?

Například heslo 123456 má SHA512:

ba3253876aed6bc22d4a6ff53d8406c6ad864195ed144ab5c87621b6c233b548baeae6956df346ec8c17f5ea10f35ee3cbc514797ed7ddd3145464e2a0bab413

Záškodník například pomocí SQL injection zjistí hash hesla, použije seznam předhešovaných hesel (Rainbow tables) a zjistí heslo 123456. Můžete namítnout, že si dám silné heslo, frázi. To je určitě dobrý nápad, ale je tu další problém. Stejná hesla mají stejný hash, toho využívají tzv. narozeninové útoky. Tento problém se řešil(ší) solením. Solením se dosáhne toho, že stejná hesla různých uživatelů mají jiné „výtahy zprávy“ (hashes). Duhové (Rainbow) tabulky fungují pouze proti nesoleným hashům.

Co solení hesel znamená?

Máme v databázi například tabulku „uzivatele“. Sloupec uzivatel, heslo a sul. Ve sloupci heslo je hash (heslo + sůl). To má za následek to, že i stejná hesla mají jiný hash.

MariaDB [redakcnisystem]> select uziv,left(heslicko,60) as heslo,sul from uzivatele;
+----------+--------------------------------------------------------------+-----------------+
| uziv | heslicko                                                     | sul             |
+----------+--------------------------------------------------------------+-----------------+
| adm     | 08421v39cak4db7995b33cee9a2525e7b8162524b235x6a809e540f6e... |l3vNhKGglrocs13< |
+----------+--------------------------------------------------------------+-----------------+

Zde máme sloupce (položky) „uziv“, „heslicko“ a „sul“. Při požadavku na přihlášení (autorizace), se po zadání účtu (uživatel) a hesla do přihlašovacího formuláře, vyhledá uživatel adm, jeho heslo a sůl. Ze zadaného hesla a soli se vytvoří SHA512 výtah zprávy a ten se porovná s uloženým sloupcem „heslicko“ na totožnost. Navíc se pozdrží autorizace o např. 1 vteřinu, nebo se chybné autorizace omezí na X pokusů, popřípadě se kombinují oba způsoby.

<?php
//...
$p = hash("sha512",$_POST['heslo'].$zaznam['sul']);
sleep(1);      // cekej 1 vteřinu
//...
?>

Takový postup je bezpečný, ale vyvstává tu další problém. Co když je solení použito nesprávně nebo chybně? Co když v budoucnu nebude stačit ani SHA512 a velikost soli? Navíc je potřeba k sloupci heslo ještě sloupec sůl. Je třeba použít také zpomalení.

Jde přihlašování (autorizace) a ukládání hesla zjednodušit?

Ano, jde. Vývojáři přišli s PHP funkcí na ukládání hesel password_hash() a funkcí na ověřování password_verify().
Funkce password_hash("moje tajne heslo", PASSWORD_DEFAULT) vytvoří osolenou hash. To si můžeme vyzkoušet:

<?php
echo password_hash("moje tajne heslo", PASSWORD_DEFAULT);
echo password_hash("moje tajne heslo", PASSWORD_DEFAULT);
?>

Výstupem password_hash() při zadání stejného hesla je vždy jiná hash:

$2y$10$eZkEdPvx/NqV6yVLGL/mSOP4hEqnd.M9prXBQ4qXbM2Q6U4KgvuLC
$2y$10$QRPl6kpudSyxW8/04Ci5n.PCox2oHht5zguKb7bzrvoHO45m0J3wC

Kdy výstup z password_hash("moje tajne heslo",PASSWORD_DEFAULT) se skládá z:

Viz srovnání SHA512, výstupem 2 x hash("sha512","moje tajne heslo") je vždy stejná hash:

ba8dbaecd78d762799715e5fe4559428a1e4b14c68ada9f5581b868c3102243fd485ef6a3239...
ba8dbaecd78d762799715e5fe4559428a1e4b14c68ada9f5581b868c3102243fd485ef6a3239...

Funkce password_hash("moje tajne heslo", PASSWORD_DEFAULT) s konstantou  PASSWORD_DEFAULT vrací hash o délce 60 znaků (rok 2022), ale doporučený sloupec v tabulce databáze je varchar(255).
Také solení a zdržení je funkcí password_hash() vyřešeno, lépe řečeno funkcí password_verify(), protože při vytváření hashe zdržovat nepotřebujeme.
Informace o vytvořené hashi lze získat z password_get_info($hash).

<?php
$heslo = "moje tajne heslo";
$hash_heslo=password_hash($heslo, PASSWORD_DEFAULT);
echo $hash_heslo."<br>";
$hashInfo = password_get_info($hash_heslo);
echo var_dump($hashInfo)."<br>";
echo "algo: ".$hashInfo['algo']."<br>";
echo "algoName: ".$hashInfo['algoName']."<br>";
echo "option['cost']: ".$hashInfo['options']['cost']."<br>";
echo "délka hashe: ".mb_strlen($hash_heslo,"utf-8")."<br>";
?>

Získáme takovýto výstup:

$2y$10$XhgNEAn5uVDyAU.0yqV.dOsyGDkJ7qtIZogBdbAwKTqLtiji7FQw2
array(3) {["algo"]=> string(2) "2y" ["algoName"]=>string(6) "bcrypt" ["options"]=>array(1) { ["cost"]=>int(10) } }
algo: 2y
algoName: bcrypt
option['cost']: 10
délka hashe: 60

Varování: Možnost soli je zastaralá. Nyní je upřednostňováno jednoduše použít sůl, která je generována ve výchozím nastavení password_hash(). Od PHP 8.0.0 je explicitně daná sůl ignorována.

Použitý algoritmus, typ a sůl jsou vráceny jako součást hashe. Proto jsou v něm zahrnuty všechny informace potřebné k ověření hodnoty hash. To umožňuje funkci password_verify() ověřit hash bez nutnosti samostatného ukládání informací o soli nebo algoritmu.


Jak porovnat hesla s password_hash() - password_verify()

Na první pohled se to může zdát složitější, ale ve skutečnosti je to zjednodušení a většinou bezpečnější. Už nemusíme v tabulce mít sloupec „sul“, přihlašování se zjednodušuje. Ale není nad praktický příklad:

<?php 
echo "<!DOCTYPE html>\n";
echo "<html lang=\"cs\">\n";
echo "<head>\n";
echo "<meta charset=\"utf-8\" />\n";
echo "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n";
echo "<meta name=\"robots\" content=\"all\" />\n";
echo "<meta name=\"keywords\" content=\"password_hash() -> password_verify()\" />\n";
echo "<meta name=\"description\" content=\"password_hash() -> password_verify()\" />\n";
echo "<meta name=\"autor\" content=\"Kocour\" />\n";
echo "<title>password_hash() -> password_verify()</title>\n";
echo "</head>\n";
echo "<body>\n";
echo "<h1>password_hash() -> password_verify()</h1>\n";
$heslo1="moje tajne heslo";                             // heslo v otevřeném tvaru
$hash_heslo=password_hash($heslo1, PASSWORD_DEFAULT);   // hash hesla (zadaným v otevřeném tvaru), obsahuje i sůl, toto se uloží do databáze
$submit="poslat";
echo "<form action=\"\" method=\"post\">\n";
echo "<fieldset>\n";
echo "<legend>Zadání hesla</legend>\n";
echo "<table>\n";
echo "<tr>\n";
echo "<td>Zadej heslo</td><td><input type=\"password\" name=\"heslo\" value=\"\" size=\"\" /></td>\n";
echo "</tr>\n";
echo "</table>\n";
echo "<br /><input type=\"submit\" name=\"".$submit."\" value=\"odeslat\" />\n";
echo "</fieldset>\n";
echo "</form>\n";

// zpracování formuláře, výpis výsledků zadání hesla  
if (!empty($_POST[$submit])) {
// tady načteme heslo z databáze a dáme do proměnné $hash_heslo
$heslo2 = $_POST['heslo'];
// porovnání hesel password_hash()-> password_verify()
// $heslo2 se zadá do formuláře, $hash_heslo se načte z databáze
if (password_verify($heslo2, $hash_heslo)) {  // porovnání hesla zadaného z formuláře (zároveň password_hash($heslo2) se správnou solí)
echo 'Správné heslo!';
} else {
echo 'Špatné heslo.';
}
}

echo "</body>\n";
echo "</html>\n";
?>

password_hash

Password_hash s defaultním nastavením ukládá hesla pomocí bcrypt.
V dnešní době je požadována „kvantově odolná“ hash, což algoritmus Argon2id splňuje a proto ho doporučuje i Národní úřad pro kybernetickou a informační bezpečnost - NÚKIB.

Password_hash s Argon2id

kvantově odolné heslo

Podle doporučení NÚKIB je nejlepší používat hesla odolná proti prolamování kvantovými superpočítači, kvantově odolná hesla, což je třeba ARGON2ID. Je to doporučený hybrid argon2d a argon2i, zdroj: NÚKIB (viz odkazy níže).

echo password_hash('tajné heslo', PASSWORD_ARGON2ID);
$argon2id$v=19$m=1024,t=2,p=2$MEhSZkJLQXUxRzljNE5hMw$33pvelMsxqOn/1VV2pnjmKJUECBhilzOZ2+Gq/FxCP4

Kde:

Závěr a doporučení

Jak vidíme z ukázky, autorizační logika se značně zjednodušila.
Proto je  dobrý nápad již používat k ukládání hesel funkci password_hash() a k ověřování hesel sesterskou funkci password_verify(). Pokud to spojíme s parametrizovanými dotazy v MySQLi, tak bude bezpečnost již na slušné úrovni.

Zajistíme si tím:

Odkazy


Komentáře

Kdokoliv může přidávat komentáře ke článkům bez registrace. Zadá si libovolnou přezdívku a napíše komentář.

Jak používat messenger Signál


SSL pro weby od 11/2015 zdarma


MS WINDOWS 10, 11 - sběr informací o uživateli


DEBIAN 12 (bookworm) - OS zdarma debian vyšel 10.6.2023

debian

debian - stáhnout nejnovější DEBIAN pro PC
debian edu - debian pro školy a školní prostředí, stažení DEBedu (torrent)


Zranitelnost „ROM-0“ routerů


Předali data tajným službám
Americké bezpečnostní agentuře (NSA) předali data Microsoft, Yahoo, Google, Facebook...


Itálie preferuje open source
Italský parlament schválil zákon, který nařizuje státním institucím pořizovat otevřený software před komerčním. To znamená LINUX místo MS-WINDOWS, LIBRE OFFICE místo MS OFFICE atd.

19.03. 2024 10:36:16
  • Redakční systém MRS
  • 10 nečastějších zranitelností WEBU
  • Esperantoesperanto - univerzální mezinárodní jazyk
  • Kryptografie okolo nás - kniha popisuje využití kryptografie v běžném životě
  • SMS zdarma - posílání SMS zdarma
  • proč LINUX
  • základy LINUXU
  • Přepsání disku náhodnými daty
  • Software na úřadech - jeho otevřené alternativy
  • Řekněte sbohem Microsoftu
  • Rychlost připojení - změřte si svoji rychlost
  • SEO servis
  • Jak psát web
  • Zákony - občanský, autorský, obchodní zákoník atd.
  • Infosoud - nalezení stání a průběhu jednání
  • Soudní rozhodnutí - nalezení rozsudků
  • ARES - registr ekonomických subjektů
  • Katastr nemovitostí
  • Broďan - brodské nezávislé zpravodajství

vydělávejte
na burze kryptoměn

23.09. 2024 07:53:51
Návštěvy
Celkem: 317062
Týden: 541
Dnes: 26
  přihlásit poslední změna: 27.09. 2024 17:03:02