crypt() ломается при переходе с PHP 5.2 на 5.4

У меня есть система, работающая на PHP версии 5.2.10. К сожалению, первоначальный программист неправильно понял, как реализована функция crypt().

$crypt = crypt(trim($cuPassword), CRYPT_BLOWFISH); 
// The programmer thought this is how you configure a blowfish cipher

nb CRYPT_BLOWFISH имеет нулевое значение на этой машине.

Это работает, поскольку создает случайный хэш пароля, например, 0$oZ534I2VvSw.

Сегодня я перенес программное обеспечение на PHP 5.4.9 и обнаружил, что $crypt становится *0, то есть ошибка из-за недопустимой соли.

Моя проблема в том, что у меня есть таблица паролей для входа в систему, которую я больше не могу проверять. Мой вопрос: есть ли способ воссоздать исходный шифр, работавший в версии 5.2? Какой хэш был реализован, когда вы передали «0» в качестве соли?


person MortimerCat    schedule 10.07.2013    source источник
comment
Дальнейший анализ: кажется, что по умолчанию CRYPT_STD_DES использует 0$ в качестве соли. Более поздняя версия PHP отвергает это как недопустимую соль.   -  person MortimerCat    schedule 10.07.2013
comment
Вы используете пластырь Suhosin? Потому что это поведение не соответствует стандартному поведению PHP из того, что я могу воспроизвести.   -  person Matthew    schedule 10.07.2013


Ответы (4)


Ваше описание действительно не сходится. В PHP 5.4.9 я тестировал это:

var_dump(crypt('hello', 0));

Вывод:

0$ny0efnQXFkE

Теперь в PHP 5.5 вы получите *0 при вызове crypt('hello', 0). Но это нормально! Поскольку это все еще верно в PHP 5.5: этот crypt('hello', '0$ny0efnQXFkE') == '0$ny0efnQXFkE'.

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

На всякий случай после успешного входа в систему проверьте, начинается ли их хэш с 0$. Если это так, перехешируйте пароль (поскольку они его ввели, вы знаете, что это такое) с обновленным, правильным вызовом шифрования.

person Matthew    schedule 10.07.2013
comment
Моя версия 5.4.9 var_dump дает строку (2) *0 - person MortimerCat; 10.07.2013
comment
crypt('hello', '0$ny0efnQXFkE') также дает мне *0 - person MortimerCat; 10.07.2013
comment
Я предполагаю, что вы используете патч Suhosin? - person Matthew; 10.07.2013
comment
Патч вроде не активен. - person MortimerCat; 10.07.2013
comment
@MortimerCat, возможно, это зависит от системной библиотеки криптографии, но, тем не менее, решение 0q выглядит как рабочее. Я бы просто обязательно перехэшировал старые пароли после входа в систему. - person Matthew; 10.07.2013

Я попробовал все допустимые комбинации из двух цифр (CRYPT_STD_DES) и обнаружил, что «0q» эквивалентно (почти).

PHP 5.2.10 crypt(trim($cuPassword), CRYPT_BLOWFISH);

Результат = 0$txv6CWBxJ9Y

PHP 5.4.9 crypt(trim($cuPassword), '0q');

Результат = 0qtxv6CWBxJ9Y

Все, что мне нужно сделать, это настроить второй символ, и я снова смогу сопоставлять пароли.

person MortimerCat    schedule 10.07.2013
comment
Я только что попробовал это самостоятельно и пришел к тому же выводу. - person Matthew; 10.07.2013

Нет, вы не можете воссоздать исходный шифр. Иначе даже бойскаут смог бы разбить иглобрюха.

Ваш лучший шанс — сгенерировать случайный пароль для ваших пользователей и хешировать его еще раз, а затем заставить их сменить пароль, как только они войдут в систему.

person ILikeTacos    schedule 10.07.2013
comment
Я не пытаюсь взломать иглобрюха, я просто пытаюсь найти параметры, которые бы генерировали тот же хеш, что и раньше. - person MortimerCat; 10.07.2013

«$» не является допустимым значением соли в соответствии с crypt(3), поэтому вам нужно найти реализацию crypt, которая так же сломана, как и та, которая раньше была в PHP/libc :)

Если проверки старых паролей достаточно, используйте ответ Мэтью, иначе попробуйте, например. openssl, который в настоящее время все еще принимает "0$" в качестве соли:

$ echo -n "secret" | openssl passwd -crypt -salt '0$' -stdin
0$z.PXBBy6uY.
person lathspell    schedule 10.07.2013