#python #django
#python #django
Вопрос:
Я создаю URL-адрес, состоящий из токена одноразового использования, и отправляю его пользователю по электронной почте. Пользователь должен щелкнуть по этой ссылке и быть перенаправлен на страницу, которая проверит токен и выполнит некоторые действия.
На стороне базы данных я сохраняю этот токен (хэшированный и соленый, по соображениям безопасности). Проблема в том, что у меня возникают некоторые трудности с проверкой токена, потому что при том, как я его сохраняю, я не могу сгенерировать ту же соль для того же токена. И, следовательно, я не могу сравнить эту соль с теми, которые я сохранил.
# Retrieving or creating object usertokens
usr, created = UserToken.objects.get_or_create(email=email)
# Adding a new token
token = uuid.uuid4().hex
usr.token = make_password(token) # Stores in the local database the salted and hashed token
usr.save()
Этот метод make_password, который я использую, определен в django.contrib.auth.hashers
.
Используя этот метод, я не могу сгенерировать два раза одну и ту же соль из одного и того же токена.
>>> token = 'test'
>>> enc_token1 = make_password(token)
>>> enc_token2 = make_password(token)
>>> enc_token1 == enc_token2
False
Это, однако, не помогает мне извлекать из моей базы данных запись, соответствующую токену, и я не могу ее проверить.
Комментарии:
1. Теперь есть кое-что, о чем я никогда раньше не слышал; Хэшированные и соленые токены . Хотите немного кетчупа с этими токенами?…..</ шутка>
2. Все шутки в сторону, цель хеширования и соления заключается в том, что исходный пароль не может быть получен из хэшированной строки. С паролями это вызывает беспокойство, потому что пароли часто каким-то образом используются повторно, и вы хотите, чтобы они оставались секретными даже долгое время после потенциального взлома. Токены можно просто сбросить, и тогда злоумышленнику абсолютно не понадобятся приобретенные токены. Как вы заметили, нет эффективного способа запросить соленый и хэшированный токен. Вот почему токены обычно хранятся в виде обычного текста. По каким конкретным соображениям безопасности вы хотите сохранить их в хешировании?
Ответ №1:
Использование простой проверки равенства строк двух хэшированных и соленых токенов не будет работать. Документы Django для управления паролями предлагают очень простой метод в django.contrib.auth.hashers
пространстве имен, который обрабатывает все это за вас:
>>> token = 'test'
>>> enc_token1 = make_password(token)
>>> check_password('test', enc_token1)
True
check_password
Метод выполняет несколько действий за капотом, например, проверяет, изменился ли алгоритм хеширования. Он возвращает результат verify
метода алгоритма BasePasswordHasher
, который реализует базовый класс. Вот пример реализации из источника PBKDF2PasswordHasher
:
def verify(self, password, encoded):
algorithm, iterations, salt, hash = encoded.split('$', 3)
assert algorithm == self.algorithm
encoded_2 = self.encode(password, salt, int(iterations))
return constant_time_compare(encoded, encoded_2)
Обратите внимание, как соль находится путем разделения encoded_string на ‘$’, поскольку в документах Django отмечается, что
Атрибут пароля пользовательского объекта представляет собой строку в этом формате:
<algorithm>$<iterations>$<salt>$<hash>
Комментарии:
1. спасибо за ответ. Проблема использования check_password заключается в том, что я должен знать как закодированную строку, так и токен. В моем случае моим вводом является токен, и я храню много закодированных строк в своей базе данных. Простите меня, если я ошибаюсь, но, если я использую метод check_password, кажется, я должен выполнить попарное сравнение между токеном и всеми сохраненными закодированными строками. Возможно, это будет дорого.
2. Помните, что алгоритм хеширования является односторонним по самой своей природе. Если вы проверяете хэши, не зная исходной строки, то вы в значительной степени нарушаете цель хэша в первую очередь, то есть не позволяете злоумышленнику, у которого есть хэши, узнать обычный текст.