2013-03-05 1 views
9

Я изучаю функцию crypt() PHP и выполняю некоторые тесты с ней. Согласно this post, я должен использовать соль длиной 22 символа. Тем не менее, я могу использовать строку длиной 23 символа с некоторыми ограничениями. Когда я использую строку длиной 22 символа, я всегда получаю результат «$ 2y $ xxStringStringStringStri.HashHashHashHashHashHashHashHas». Я знаю, что этот период - только часть соли.Почему я не должен использовать 23-й символ в солите функции crypt()?

Кажется, что если я использую 23 символа вместо 22, я могу успешно сгенерировать разные хэши, но для всех 64 символов есть только 4 разных результата. 23-й символ «округляет» с точностью до 1/4 из 64 символов алфавита (например, 23-й символ «W» и округляется до «O» или любое число округляется до «U»)

v---------------v---------------v---------------v--------------- 
./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890 

Все четыре из этих крипт функций порождают ту же соль:

crypt('Test123','$2y$09$AAAAAAAAAAAAAAAAAAAAAq'); 
crypt('Test123','$2y$09$AAAAAAAAAAAAAAAAAAAAAr'); 
crypt('Test123','$2y$09$AAAAAAAAAAAAAAAAAAAAAs'); 
crypt('Test123','$2y$09$AAAAAAAAAAAAAAAAAAAAAt'); 

Но это одна другая:

crypt('Test123','$2y$09$AAAAAAAAAAAAAAAAAAAAAu'); 

Так почему я не должен использовать 23-й символ, когда он может успешно генерировать разные результаты? Есть ли какое-то глючное поведение в PHP, которого следует избегать, не используя его?

Для выяснения того, как я рассчитываю на 23-й символ в соли:

crypt('Test123','$2y$08$ABCDEFGHIJKLMNOPQRSTUV'); 
//  The salt is '$ABCDEFGHIJKLMNOPQRSTUV' 
//  Which will be treated as '$ABCDEFGHIJKLMNOPQRSTUO' 
+1

Есть хорошее объяснение по этому вопросу: http://security.stackexchange.com/questions/20862/php-crypt-trims-the-salt-as-it-would-be-too-long –

+0

Благодарим вас за этот ответ. Хотя это касается только того, что происходит с 23-м символом, поскольку он только сокращается из-за размера бит, разрешенного в функции crypt(). Мой вопрос, по-другому, спросить: «Должен ли я использовать 23-й символ, даже если он будет расколоться на два бита?» или другой способ: «Есть ли глюк в алгоритме PHP, который генерирует неправильные хэши всякий раз, когда используется 23-й символ?» – Andrew

ответ

2

Это связано с хэш-коллизий. После того, как вы превысите 22 символа, созданные вами хэши уже не уникальны в зависимости от алгоритма NAMESPACE. Другими словами, более 22 символов не приводят к повышению безопасности и могут фактически снизить уровень безопасности.

+1

Мне кажется, что он добавляет еще 2 бит безопасности. Я все еще могу генерировать разные хэши, изменяя другие символы по всей соли, оставляя 23-й, как, скажем, «а». Есть статья о переполнении соли? Даже на [php.net] (http://php.net/manual/en/function.crypt.php) они используют пример соли с более чем 22 символами. – Andrew

+1

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

+0

Хммм .... Я не знаю, как это объяснить, но я могу гарантировать, что использование 23 символов в соли (даже если есть солевые столкновения, как вы сказали) более безопасно, чем использование 22. Объяснение: Предположим, мы имеем меньшую форму blowfish. В этой мини-луковице мы можем положить соль длиной 1 символ, такую ​​как «a» или «4» или «I».Есть 64 различных сочетания, которые мы можем сделать с этим, прежде чем мы начнем получать солевые столкновения. Однако мы можем добавить только 2 бита («.», «O», «e» и «u») и превратить комбинацию из 64 уникальных солей в 256. Даже если это не полный алфавит, он более безопасен. – Andrew

0

$ не является частью настоящей соли. Это разделитель.

Для склепа Blowfish формат $ 2 [axy] $ log2Rounds $ [соль] [hash]. Вы описываете его добавление a. - это потому, что вам не хватает последнего персонажа. Соль Blowfish составляет 128 бит. Вы можете использовать только 126, да, но вы просто излишне ослабляете соль.

+0

Если вы действительно используете слишком много символов, кстати, вы отлично справляетесь с crypt(), потому что он предназначен для использования в качестве crypt (password, salt) для crypt, cryptedPassword == crypt (password, cryptedPassword) для проверки, и он делает это, добавляя хэш к соли на выходе и используя только соответствующие солевые байты на входе. Таким образом, вы видите, что дополнительные символы просто не будут использоваться. – Zer