У меня есть хэши паролей, хранящиеся в базе данных Postgresql, сгенерированные с помощью:
password_hash($password, PASSWORD_DEFAULT);
Теперь я хотел бы также иметь возможность проверить пароль пользователя с помощью Postgresql и pgcrypto.
Но функция pgcrypto crypt()
не может проверить существующие хэши паролей.
Однако я могу проверить хэши паролей, сгенерированные Postgresql, с помощью PHP password_verify
.
Например:
password_hash('hello', PASSWORD_DEFAULT);
$2y$10$fD2cw7T6s4dPvk1SFHmiJeRRaegalE/Oa3zSD6.x5WncQJC9wtCAS
postgres=# SELECT crypt('hello', gen_salt('bf'));
crypt
--------------------------------------------------------------
$2a$06$7/AGAXFSTCMu9r.08oD.UulYR0/05q7lmuCTC68Adyu/aNJkzpoIW
Проверка:
// php_verify with the Postgresql hash
php > var_dump(password_verify('hello', '$2a$06$7/AGAXFSTCMu9r.08oD.UulYR0/05q7lmuCTC68Adyu/aNJkzpoIW'));
bool(true)
postgres=# SELECT crypt('hello', '$2y$10$fD2cw7T6s4dPvk1SFHmiJeRRaegalE/Oa3zSD6.x5WncQJC9wtCAS');
crypt
---------------
$2JgKNLEdsV2E
(1 Zeile)
Мои вопросы в основном:
Из ответа на: Где используется префикс 2x в BCrypt?, в котором есть все кровавые подробности о вариантах $2$, порожденных ошибками реализации:
There is no difference between 2a, 2x, 2y, and 2b. If you wrote your implementation correctly, they all output the same result.
Исходя из этого, можно взять хеш, сгенерированный PHP password_hash
, заменить начальный $2y$
на $2a$
и передать его в качестве второго аргумента pgcrypto crypt()
.
Используя значение из вашего примера:
postgres=# \set hash '$2a$10$fD2cw7T6s4dPvk1SFHmiJeRRaegalE/Oa3zSD6.x5WncQJC9wtCAS'
postgres=# SELECT crypt('hello', :'hash') = :'hash'
?column?
----------
t
Вау... Спасибо, что поделились/расследовали это!
$2y$
— это специфичный для PHP алгоритм, поскольку в его$2a$
реализации была ошибка, IIRC. Проблема, вероятно, в том, что очень немногие другие системы поддерживают его.