Как проверить Cookie Token против bcrypt-хэшированного токена в БД при использовании Persistent Login Cookies?

В это популярное решение для постоянных файлов cookie для входа, которое включает в себя создание случайного 128-разрядного "токена" для сохранения в пользовательском Cookie, Йенс Роланд рекомендует:

И НЕ ЗАПУСКАЙТЕ СТОЙНУЮ ТОЧКУ ВХОДА (ТОКЕН) В ВАШЕЙ БАЗЕ ДАННЫХ, ТОЛЬКО ХАШ ЭТО! Ток входа - это эквивалент пароля, поэтому, если злоумышленник получил доступ к вашей базе данных, он может использовать токены для входа в любую учетную запись, как если бы они были чистыми комбинации паролей-паролей. Поэтому используйте сильное соленое хеширование (bcrypt/phpass) при сохранении постоянных токенов входа.

Но как вы проверяете токен Cookie против bcrypted Token в БД, чтобы подтвердить, что вход в Cookie действителен, когда bcrypting Token Cookie всегда даст другой результат (так как bcrypting всегда использует случайную соль)?

Другими словами, вы не можете просто шифровать токен Cookie и искать совпадение в БД, так как вы его никогда не найдете, так как вы на самом деле сопоставляете его с хеш-версией в БД в соответствии с рекомендуемое решение ( "Сервер хранит таблицу из числа → ассоциаций имени пользователя, которая проверяется на достоверность файла cookie." )?

Edit:

Имейте в виду, что в соответствии с рекомендуемым решением, связанным выше, один пользователь может иметь несколько Cookies/токены для разных устройств. Я упоминаю об этом, потому что был отправлен ответ (который с тех пор был удален), который предположил, что это только один токен на пользователя.

Ответ 1

Как упоминалось в предыдущем ответе, bcrypt сохраняет случайную соль как часть хэша, поэтому каждая запись маркера в вашей базе данных будет включать как random_salt, так и hashed_token.

При аутентификации "cookie cookie" "Запомнить меня" (который должен состоять из userid и token) вам нужно будет перебирать каждую из записей токена для этого идентификатора пользователя (обычно только одна запись, не более горстка) и проверять каждый отдельно, используя сохраненную случайную соль:

foreach (entry in stored_tokens_for_user) {
    if (entry.hashed_token == bcrypt(cookie.token, entry.random_salt))
        return true;
}
return false;

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