Elég biztonságos, ha egy sima adatbázisba az alábbi módon mentem el a jelszavakat?
Hobbi szinten tanulok MySQL-t. Létrehoztam egy táblát, amiben van egy felhasználó azonosító(primary key), egy felhasználó név, egy e-mail és egy jelszó mező(később majd még valószínűleg kiegészítem valamikkel, de ez jelenleg nem lényeg szerintem). Természetesen egy PHP fájlt is készítettem, amin keresztül bekérem az adatokat. A jelszó mezőhöz sha2 titkosítást használnék, mint az alábbi példákban:
Sha2 nem biztonságos és nem sózott.
Jelszó törésre/kiderítésre vannak úgy nevezett rainbow táblák (amit kvázi bárki csinálhat), amik megmondják melyik jelszó-hashhez melyik szóösszetétel való. Ez azért kivitelezhető, mert ugyanazt a jelszót vagy szöveget külön-külön többszőr hash-elve is ugyanazt kapod, attól függetlenül, hogy te vagy én hashelek.
Sózott jelszóval már nem. Ott minden jelszó titkosításnak más az output-ja. Most (tudtommal) a legbiztonságosabbnak tartott algoritmus az Argon2id.
Nézzük az elterjedtebb rossz és kevésbé rossz megoldásokat:
1. Jelszó tárolása egyszerű szövegként. Mondani sem kell, ha valaki csak olvasási joggal hozzáfér az adatbázishoz, akkor viszi az összes felhasználó jelszavát.
2. Jelszó tárolása valamilyen hash-el. Vegyük példának az md5-öt, ami nem teljesen biztonságos, de egy még biztonságosnak mondható hash algoritmussal is ugyanezek a problémák merülnek fel, tehát ez itt most az md5 nem biztonságos volta nem annyira releváns. Pl. md5($password). Vannak un. szivárványtáblák, amivel a szótári szavakat, egyszerűbb, rövidebb jelszavakat ki lehet keresni egy adatbázisból.
2.5. Van, aki azt gondolja, hogy ha a hash függvényeket egymásba ágyazza, azzal növeli a biztonságot. Pl.: md5(md5($password)). Valójában nem, ez érdemben nem teszi biztonságosabbá a jelszó tárolását.
3. Jelszó „sózása” fix utótaggal. Pl.: md5($password . md5($secret_constant)). Ez azért jó, mert ez egy rövid jelszóból is hosszút csinál, így a jelszótárolás módjának ismerete nélkül nyers erővel (brute force) kvázi feltörhetetlenné teszi a jelszót. A probléma ezzel az, hogy minden jelszót ugyanazzal a sóval sózod be, így a gyakori jelszavaknak (pl. "password123") az így hash-elt változata is azonos lesz, így az adatbázis birtokában a gyakori jelszavak jó eséllyel fejthetők vissza. Illetve a gond ott kezdődik, ha valakinek sikerül megszereznie a jelszó kódolásának módját, neadjisten a titkos sót is.
4. Jelszó sózása valamiféle változó adattal. Pl. a felhasználó azonosítóval, email címmel, de még jobb, ha egy random stringgel, amit prefixumként megkap a jelszó. Pl.:
$salt = md5($email . random_int());
$password_hash = $salt . '$' . md5($password . $salt);
Ellenőrzéshez meg:
list($salt, $hash) = explode('$', password_hash, 2);
$password_match = $hash == md5($login_password . $salt);
Ez már elég közel áll az ideálishoz.
De van itt egy alapvető koncepcionális probléma. A hagyományos hash függvények (md5, sha1, sha2, sha256 és társaik) általános célúak. Használják pl. fájlok tartalomfüggő azonosítására, ellenőrzőösszegre is. Emiatt úgy alakították ki őket, hogy gyorsak legyenek, akár többszállúsíthatóak legyenek. Ez egy 5 GB-os fájl kvázi ellenőrzőösszegének kiszámolásánál nagy előny, de a jelszavaknál pont hátrány, hiszen egységnyi idő alatt nagyon sok próbálkozást lehet eszközölni egy brute force eljárással.
Meg ezek mind barkács megoldások, neked kell megírni az extra köröket hozzá.
~ ~ ~
A PHP tartalmaz néhány egyszerű beépített függvényt a jelszavak erős, biztonságos hash-elésére. Lásd: [link]
Ez egy lassú, számításigényes, nem párhuzamosítható hash algoritmusokkal dolgozik, így a brute force nehézkesen fog menni, sokba kerül. Nem kell semmi extra kör, pl. a sózást elvégzi maga.
Regisztrációnál:
$password_hash = password_hash($plain_password);
(Lehet még hash algoritmust választani, meg lehet azt paraméterezni, de jelenleg az alapértelmezett paraméterekkel is kellően jó lesz. Paraméterezni akkor érdemes, ha tudod hogy mit csinálsz és miért csinálod.)
Bejelentkezésnél:
$password_match = password_verify($login_password, $password_hash);
Ha paraméterezed is a password_hash függvényt, és várható, hogy változtatni fogod a paramétereket, akkor bejelentkezésnél:
$password_match = password_verify($login_password, $password_hash);
if (password_match) {
if (password_needs_rehash($password_hash, $algo, $options) {
$new_password_hash = password_hash($login_password, $algo, $options);
// A tárolt jelszó hash frissítése az adatbázisban az újragenerált hash-el.
}
}
Annyi szemléletváltást igényelhet a dolog, SQL-ben úgy kell összeállítani a SELECT-et, hogy feltételnek kizárólag a felhasználó nevét / email címét / egyéb azonosítóját adod meg a WHERE-nél:
SELECT email, name, akármi, password_hash
FROM users
WHERE email='gipszjakab@gmail.com'
Magának a jelszónak az egyezőségét nem az SQL-lel ellenőrzöd, hanem a fentiek alapján.
Kapcsolódó kérdések:
Minden jog fenntartva © 2024, www.gyakorikerdesek.hu
GYIK | Szabályzat | Jogi nyilatkozat | Adatvédelem | Cookie beállítások | WebMinute Kft. | Facebook | Kapcsolat: info(kukac)gyakorikerdesek.hu
Ha kifogással szeretne élni valamely tartalommal kapcsolatban, kérjük jelezze e-mailes elérhetőségünkön!