Сохраненный соленый токен и сравнение токенов

#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. Помните, что алгоритм хеширования является односторонним по самой своей природе. Если вы проверяете хэши, не зная исходной строки, то вы в значительной степени нарушаете цель хэша в первую очередь, то есть не позволяете злоумышленнику, у которого есть хэши, узнать обычный текст.