2010-09-29 3 views
17

Я использую PHP crypt() как способ хранения и проверки паролей в моей базе данных. Я использую хэширование для других вещей, но crypt() для паролей. Документация не так хороша, и, похоже, много дебатов. Я использую blowfish и две соли, чтобы склеить пароль и сохранить его в базе данных. Прежде чем я сохраню соль и зашифрованный пароль (например, соленый хэш), но осознал его избыточность, потому что соль является частью зашифрованной строки пароля.Я правильно использую функцию crypt() PHP?

Я немного смущен тем, как атаки радужного стола будут работать на crypt(), так или иначе это выглядит правильно с точки зрения безопасности. Я использую вторую соль, чтобы добавить к паролю, чтобы увеличить энтропию коротких паролей, возможно, перебор, но почему бы и нет?

function crypt_password($password) { 
if ($password) { 
    //find the longest valid salt allowed by server 
    $max_salt = CRYPT_SALT_LENGTH; 

    //blowfish hashing with a salt as follows: "$2a$", a two digit cost parameter, "$", and 22 base 64 
    $blowfish = '$2a$10$'; 

    //get the longest salt, could set to 22 crypt ignores extra data 
    $salt = get_salt ($max_salt); 

    //get a second salt to strengthen password 
    $salt2 = get_salt (30); //set to whatever 


    //append salt2 data to the password, and crypt using salt, results in a 60 char output 
    $crypt_pass = crypt ($password . $salt2, $blowfish . $salt); 

    //insert crypt pass along with salt2 into database. 
    $sql = "insert into database...."; 

    return true; 
    } 
} 


function get_salt($length) { 
$options = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz./'; 

$salt = ''; 

for($i = 0; $i <= $length; $i ++) { 
    $options = str_shuffle ($options); 
    $salt .= $options [rand (0, 63)]; 
} 
return $salt; 
} 

function verify_password($input_password) 
{ 
if($input_password) 
{ 
    //get stored crypt pass,and salt2 from the database 
    $stored_password = 'somethingfromdatabase'; 
    $stored_salt2 = 'somethingelsefromdatabase'; 

    //compare the crypt of input+stored_salt2 to the stored crypt password 
    if (crypt($input_password . $stored_salt2, $stored_password) == $stored_password) { 
     //authenticated 
     return true; 
    } 
    else return false; 
} 
else return false; 
} 
+0

Использование 'mt_rand' вместо' rand' будет немного улучшить ваш скрипт – Sliq

ответ

15

Вы действительно должны взглянуть на PHPASS: http://www.openwall.com/phpass/ Это система хэширования паролей с использованием crypt(), которая используется в таких проектах, как Wordpress и phpBB.

Существует также отличная статья на этом сайте о хэшировании паролей, соление и растяжении, используя склеп(): http://www.openwall.com/articles/PHP-Users-Passwords

UPDATE: В настоящее время существует альтернатива для библиотеки PHPASS. В следующей версии PHP существуют специальные функции для хэширования и проверки паролей (с использованием bcrypt): http://www.php.net/manual/en/ref.password.php. Существует библиотека совместимости, которая реализует эти функции для PHP 5.3.7+: https://github.com/ircmaxell/password_compat

+1

Я могу видеть, как эта структура может быть полезна для подхода, находящегося вне коробки, но я не вижу много различий между моим кодом и кодом кода кода. – Brian

+1

И: PHPass - это беспорядок. Массивный беспорядок. Это так беспорядочно, что я не буду на это полагаться. – Sliq

+0

@ Panique вы бы хотели объяснить? –

3

Идея стола радуги заключается в том, что злоумышленник может сделать стол со всеми возможными паролями и их хэшами дома.

E.g.

PASSWORD HASH 
iloveSO gjroewjgo 
password knbnogjwm 
secret gjroehghe 
jbieber rewgroewj 

т.д.

С помощью этой таблицы, злоумышленник может быстро преобразовать любой хэш пароля. В таблице Rainbow используются некоторые трюки, поэтому не все хеши нужно хранить, но они все еще заранее вычисляют все хэши.

Используя соль, даже если вы храните ее с паролем, вы делаете это намного сложнее. Вместо того, чтобы хешировать каждое слово в словаре, злоумышленнику теперь нужно будет хешировать каждое слово с каждой солью. При наличии достаточно соли, это дает достаточно комбинаций, чтобы сделать невозможным вычисление всех этих хешей.

Так что соль не должна быть дополнительным паролем, известным только приложению, он предназначен для изменения хеш-функции, так что он нестандартен.

+0

Он использует соль, но неизвестной длины. При значительном большом значении соли такой радужный стол был бы неосуществим. Например, 256^256 или соль base256 из 256 байтов настолько велика, что у нас даже нет слова для такого количества байтов, которое требуется для взлома пароля только одного символа. – rook

2

Это неправильное использование crypt(), потому что вы используете устаревший примитив. Blowfish очень старый, twofish - замена, и даже это старое, потому что три рыбки почти завершены. Вы должны использовать члена семейства sha2, sha256 или sha512 - оба хороших варианта. crypt() можно использовать с sha256 или sha512, вы должны использовать CRYPT_SHA256 CRYPT_SHA512 параметры соответственно.

Также у ваших солей очень небольшое отношение энтропии/размера, вы используете только буквенно-цифровой набор, который является шуткой, потому что алфавитно-цифровые таблицы радуги являются наиболее распространенными. Вы должны использовать полный байт, который base256, и я рекомендую соль длиной 256 байтов. Имейте в виду, что все хеш-функции являются бинарно безопасными по определению, поэтому вам не нужно беспокоиться о нулевых байтах и ​​т. П.

+0

Blowfish может принимать только буквенно-цифровые символы, поэтому, возможно, я должен использовать CRYPT_SHA512. – Brian

+0

@Brian Perin then thats что-то странное с crypt(), потому что блочные шифры используются для шифрования файлов и трафика все время. – rook

+2

Blowfish, используемый 'crypt()', не совсем то же самое, что и старый блочный шифр Blowfish - это вариантный алгоритм, специально созданный для хэширования/вывода пароля. – caf

11

Ваше использование crypt() в порядке. crypt($input, $stored) == $stored - это способ, которым он предназначен для использования.

Ваша функция get_salt() невелика, так как используется часто бедный rand(). Вместо этого следует использовать более сильную случайную функцию, например openssl_random_pseudo_bytes().

0

Используйте SHA-512 (если имеется) с солью, которая включает время() и openssl_random_pseudo_bytes(). Crypt является консолидированным/эффективным, потому что он возвращает соль, вставленную с хешированной строкой.