Jak zaimplementować salt do mojego loginu dla haseł?

Chcę zaimplementować salt do mojego systemu logowania, ale jestem trochę zdezorientowany, jak to ma działać. Nie rozumiem logiki. Rozumiem, że md5 jest algorytmem jednokierunkowym i wszystkie funkcje, na które się natknąłem, wydają się łączyć wszystko razem. Jeśli tak jest, w jaki sposób można odzyskać hasło do porównania? Moim największym pytaniem jest, w jaki sposób solenie hasła użytkownika jest bezpieczniejsze niż tylko hashowanie hasła? Jeśli baza danych kiedykolwiek miała być zagrożona, hash wraz z solą jest w bazie danych. Czy to nie wszystko, czego potrzebuje haker?

Znalazłem też inny post tutaj NA SO gdzie inny deweloper powiedział:

"upewnij się, że Twoja sól i algorytm są przechowywane oddzielnie od bazy danych "

Chciałbym przechowywać sól w bazie danych. Czy to naprawdę problem?

Szukam pomocy w zrozumieniu, jak to działa i jaka może być najlepsza praktyka. Każda pomoc jest bardzo doceniam to.


Edytuj: Dziękuję wszystkim za odpowiedzi i pomysły. Mimo, że mogę być bardziej zdezorientowany teraz, to z pewnością było doświadczenie uczenia się dla mnie. Jeszcze raz dzięki chłopaki.

Author: JabberwockyDecompiler, 2010-02-03

8 answers

Funkcja hash zawsze zwraca tę samą wartość dla tego samego ciągu wejściowego. Załóżmy, że mój użytkownik (Alicja) ma hasło secret. Hashowanie secret za pomocą md5() prowadzi do następującego hasha

5ebe2294ecd0e0f08eab7690d2a6ee69

Używając słownika (listy popularnych słów i haseł) lub jednej z różnych stron, które oferują tę usługę, atakujący (Mallory) może łatwo dowiedzieć się, że hasło jest tajne, gdy zobaczy w swoim słowniku, że 5ebe2294ecd0e0f08eab7690d2a6ee69 = secret.

[[12]}proces solenia przed mieszaniem sprawia, że trudniej użyć ataku słownikowego bez znajomości soli. Rozważmy następujące:
<?php
$salt = '@!#%$@#$@SADLkwod,sdaDwqksjaoidjwq@#@!';
$hash = md5($salt . 'secret');

Wynikowy hash jest teraz b58ad809eece17322de5024d79299f8a, ale hasło Alice jest nadal secret. Jeśli Mallory dostanie solony haszysz, jest szansa, że nie znajdzie odpowiedzi w swoim słowniku. Jeśli to zrobi, słownik da jej złą odpowiedź.

Nigdy nie przechowuj soli statycznej w bazie danych. Najlepiej przechowywać go z konfiguracją aplikacji (która przy okazji nie powinna być dostępne w Internecie).

Jeśli zamierzasz użyć dynamicznego salt, będziesz musiał użyć bazy danych. Użyj niezerowej kolumny istniejących ważnych danych, aby zbudować swój salt (Blowfish-zaszyfrowany łańcuch nazwy użytkownika oparty na tajnym kluczu szyfrowania jest zwykle bezpieczny kryptograficznie). Nie używaj oddzielnej kolumny do soli. Jeśli nie możesz użyć istniejącej kolumny, włącz sól do tej samej kolumny niż hash. Na przykład użyj pierwszych 32 znaków dla 128-bitów sól i ostatnie 40 za 160 bitów haszu. Następująca funkcja wygeneruje taki hash:

function seeded_sha1($string, $seed_bits) {
    if(($seed_bits % 8) != 0) {
        throw new Exception('bits must be divisible by 8');
    }

    $salt = '';
    for($i = 0; $i < $seed_bits; $i+=8) {
        $salt .= pack('c', mt_rand());
    }

    $hexsalt = unpack('h*hex', $salt);

    return $hexsalt['hex'] . sha1($salt . $string);
}

function compare_seeded_sha1($plain, $hash) {
    $sha1 = substr($hash, -40);
    $salt = pack('h*', substr($hash, 0, -40));

    $plain_hash = sha1($salt . $plain);
    return ($plain_hash == $sha1);
}

Jeśli atakujący dostanie się do twojej bazy danych za pomocą SQL injection, przynajmniej odzyskane przez niego skróty nie będą przydatne, ponieważ nie będzie miał dostępu do konfiguracji Twojej aplikacji. Jeśli twój serwer zostanie zakorzeniony, to prawie koniec gry bez względu na to, co robisz.

Uwaga: możliwe są inne rodzaje ataków na md5() dlatego używasz więcej bezpieczny algorytm haszujący, sha1() na przykład. A nawet lepiej, Użyj Portable PHP password hashing framework , który został zaprojektowany z myślą o bezpieczeństwie i jest wstecznie kompatybilny z praktycznie każdą wersją PHP.

require('PasswordHash.php');

$pwdHasher = new PasswordHash(8, FALSE);

// $hash is what you would store in your database
$hash = $pwdHasher->HashPassword( $password );

// $hash would be the $hashed stored in your database for this user
$checked = $pwdHasher->CheckPassword($password, $hash);
if ($checked) {
    echo 'password correct';
} else {
    echo 'wrong credentials';
}
 18
Author: Andrew Moore,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-03 17:20:07

Celem salt jest uniemożliwienie atakującym amortyzacji kosztów ataku brute force w różnych witrynach (lub jeszcze lepiej, gdy używa się innego salt dla każdego użytkownika: Wszystkich użytkowników witryny) poprzez wstępnie obliczone rainbow tables.

Za pomocą zwykłego hashowania atakujący może obliczyć taką tabelę raz (bardzo długa, kosztowna operacja), a następnie użyć jej do szybkiego znalezienia haseł dla dowolnej witryny. Gdy strona używa jednej stałej soli, atakujący musi obliczyć nową tabelę specjalnie dla tego miejscu. Gdy witryna używa innej soli dla każdego użytkownika, atakujący może przestać zadręczać się rainbow tables - będzie musiał brutalnie wymusić każde hasło osobno.

Przechowywanie soli oddzielnie nie jest konieczne, aby uzyskać tę przewagę. Teoretycznie byłoby to jeszcze bardziej bezpieczne, ponieważ zneutralizowałoby słabość słownika czy krótkich haseł. W praktyce nie warto się tym przejmować, bo na koniec dnia trzeba mieć dostęp do soli gdzieś , aby sprawdzić hasła. Ponadto próba ich oddzielenia doprowadziłaby do powstania bardziej złożonych systemów - a im bardziej skomplikowany jest system, tym większe są możliwości występowania luk w zabezpieczeniach.

Edit: moje konkretne zalecenia:

  • Wygeneruj długi pseudorandom soli dla każdego użytkownika i przechowuj w DB
  • użyj hasha opartego na bcrypt
  • najlepiej, nie wdrażaj go samodzielnie, użyj istniejącej biblioteki zamiast
 31
Author: Michael Borgwardt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-03 00:36:44

Zapomnij o używaniu soli (częściowo z powodu, o którym wspominasz), użyj zamiast tego bcrypt:

Aby uzyskać dobre wyjaśnienie Zobacz: http://codahale.com/how-to-safely-store-a-password/

 14
Author: Rich,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-02 23:22:13

Inne odpowiedzi są dobre, więc dorzucę drobną kwestię, o której nikt inny nie wspomniał. Nie chcesz używać tego samego soli dla każdego hasła, ponieważ jeśli dwie osoby mają to samo hasło, będą miały ten sam hash. To ujawnienie informacji, które napastnik może wykorzystać.

Można by użyć tej samej soli dla każdego użytkownika wraz z dobrym pomysłem Juraja, aby połączyć hasło z innymi nie zmieniającymi się polami bazy danych (unikalnymi dla użytkownika). Ale uważaj, bo to informacje są powiązane z hasłem. Jeśli mielibyście hashować nazwę użytkownika i hasło razem, aby zagwarantować unikalny hash, nie mielibyście możliwości zmiany nazwy użytkownika bez utworzenia nowego użytkownika i wymagania od niego ustawienia nowego hasła.

Jako przykład posiadania unikalnej soli na użytkownika i przechowywania jej obok hasha hasła, wskażę /etc/shadow na typowym systemie Linux.

root@linux:/root# cat /etc/shadow | grep root
root:$1$oL5TTZxL$RhfGUZSbFwQN6jnX5D.Ck/:12139:0:99999:7:::

Tutaj oL5TTZxL jest solą i RhfGUZSbFwQN6jnX5D.Ck / jest hash. W tym przypadku hasło tekstowe to root, a algorytm hashowy, którego używa mój system, to oparty na MD5 algorytm haseł BSD. (nowsze systemy niż moje mają lepsze algorytmy haszujące)

 7
Author: indiv,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-03 00:41:48

Nie wyciągasz hasła do porównania. Szyfrujesz hasło podczas próby logowania i porównujesz zapisaną wartość z nowo zaszyfrowaną wartością.

 5
Author: brian,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-02 23:19:01

Jak wspomniałeś, algorytmy haszujące działają tylko w jedną stronę (lub tylko wtedy, gdy są wystarczająco silne :-D)

Dla Twojego pytania o solowanie polecam hashowanie hasła za pomocą statycznego łańcucha soli i niektórych dynamicznych danych z bazy danych , które powinny nie zmieniać po raz utworzony

Jest to bardzo bezpieczny sposób przechowywania haseł, ponieważ nawet jeśli baza danych jest zagrożona, hakerzy / krakerzy nadal muszą uzyskać statyczny hash string i muszą odgadnąć, jak to zrobić zastosowałem całe solenie..

Na przykład załóżmy, że masz users tabelę z tymi kolumnami:

id
username
password
created_at

Kolumny id i created_at Po wypełnieniu nigdy nie powinny być zmieniane..

Więc kiedy hasasz hasło użytkownika, możesz zrobić tak prosto, jak:

<?php
    $staticSalt = '!241@kadl;ap][';
    $userPass = 'my new pass';
    // assuming $user variable is already populated with DB data
    // we will generate new hash from columns and static salt:
    $genPass = sha1($user['id'] . $userPass . $user['created_at'] . $staticSalt);
?>

Mam nadzieję, że ten pomoże :) pozdrawiam

 2
Author: Juraj Blahunka,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-02 23:28:24

Hashowanie haseł ma na celu zachowanie tych haseł w tajemnicy przed własnymi administratorami.

1) utrzymywanie haseł tekstowych w bazie danych byłoby w porządku, chyba że hasła mogą być używane przez administratora, aby uzyskać dostęp do innego systemu.

2) możesz użyć pojedynczego globalnego salt, który jest łączony z hasłami (przez prepending lub XORing), a następnie hashuje do przechowywania w bazie danych. Ale to jest podatne na złośliwego administratora i tęczę stół przeznaczony do tej soli.

3) możesz mieć oddzielny salt dla każdego użytkownika: baza danych będzie używana do przechowywania salt, a hash pochodzi z kombinacji hasło / salt. Zapobiegnie to atakowi tęczy, ale ataki brute force nadal będą możliwe.

4) wreszcie, możesz zachować swoją funkcję hash w tajemnicy, używając rozwiązania haszującego sprzętowego o ograniczonej prędkości.

To najlepiej, jak potrafisz. Ze względu na ludzką naturę hasła mają ograniczoną domenę i są podatne na ataki brute force. Staramy się uniemożliwić administratorom przechwytywanie haseł użytkowników, a następnie używanie ich na innych systemach, do których nie powinni mieć dostępu.

Inne uwagi:

A) możesz użyć bcrypt na kombinacji hasło / sól, aby spowolnić atak brute force atakującego. Ale skoro Zakładamy administratorów, mogą być cierpliwi.

B) oddzielenie soli od hasha hasła nie jest skuteczną obroną, jesteśmy zakładając jednak administratorów.

C) wykorzystanie istniejących danych jako soli jest trochę lepsze, ale wątpię, aby istniejące dane miały tyle entropii, ile ma przypadkowa sól.

 2
Author: Kyle Lahnakoski,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-03 01:04:58

Zasolenie hasła użytkownika jest prawdopodobnie bezpieczniejsze niż tylko hashowanie hasła, ponieważ może chronić przed atakami prekomputacyjnymi.

Na przykład, jeśli haker uzyska dostęp do twojej bazy danych, a hasła nie zostaną zasolone, może wyszukać hashe w swojej bazie danych (zobacz http://en.wikipedia.org/wiki/Rainbow_table ), Aby uzyskać oryginalne hasła.

 1
Author: Sam Hartsfield,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-02 23:27:25