Подтвердить что ты не робот

Соль и хэш-пароль в Python

Этот код должен хешировать пароль с солью. Соль и хешированный пароль сохраняются в базе данных. Сам пароль не является.

Учитывая деликатный характер операции, я хотел убедиться, что все было кошерным.

import hashlib
import base64
import uuid

password = 'test_password'
salt     = base64.urlsafe_b64encode(uuid.uuid4().bytes)


t_sha = hashlib.sha512()
t_sha.update(password+salt)
hashed_password =  base64.urlsafe_b64encode(t_sha.digest())
4b9b3361

Ответ 1

РЕДАКТИРОВАТЬ: Этот ответ неверен. Одна итерация SHA512 быстрая, что делает ее неподходящей для использования в качестве функции хеширования пароля. Вместо этого используйте один из других ответов.


Выглядит хорошо у меня. Тем не менее, я уверен, что вам на самом деле не нужен base64. Вы можете просто сделать это:

import hashlib, uuid
salt = uuid.uuid4().hex
hashed_password = hashlib.sha512(password + salt).hexdigest()

Если это не создает трудностей, вы можете получить немного более эффективное хранилище в своей базе данных, храня солт и хешированный пароль в виде необработанных байтов, а не шестнадцатеричных строк. Для этого замените hex на bytes а hexdigest на digest.

Ответ 2

Основываясь на других ответах на этот вопрос, я реализовал новый подход с использованием bcrypt.

Зачем использовать bcrypt

Если я правильно понимаю, аргумент для использования bcrypt над SHA512 заключается в том, что bcrypt разработан для медленной работы. bcrypt также есть возможность настроить, насколько медленно вы хотите, чтобы при генерации хешированного пароля в первый раз:

# The '12' is the number that dictates the 'slowness'
bcrypt.hashpw(password, bcrypt.gensalt( 12 ))

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

Реализация

def get_hashed_password(plain_text_password):
    # Hash a password for the first time
    #   (Using bcrypt, the salt is saved into the hash itself)
    return bcrypt.hashpw(plain_text_password, bcrypt.gensalt())

def check_password(plain_text_password, hashed_password):
    # Check hashed password. Using bcrypt, the salt is saved into the hash itself
    return bcrypt.checkpw(plain_text_password, hashed_password)

Заметки

Мне удалось довольно легко установить библиотеку в системе Linux, используя:

pip install py-bcrypt

Тем не менее, у меня было больше проблем при установке его на мои системы Windows. Похоже, нужен патч. См. Этот вопрос: установка py-bcrypt на win 7 64bit Python

Ответ 3

Умная вещь - не писать криптому себя, а использовать что-то вроде passlib: https://bitbucket.org/ecollins/passlib/wiki/Home

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

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

Также только один раунд sha512 более уязвим для атак со словарем. sha512 разработан, чтобы быть быстрым, и это на самом деле плохо, когда вы пытаетесь безопасно хранить пароли. Другие люди думали долго и упорно о всех такого рода проблем, так что лучше воспользоваться этим.

Ответ 4

Для этого в Python 3 вам понадобится кодировка UTF-8, например:

hashed_password = hashlib.sha512(password.encode('utf-8') + salt.encode('utf-8')).hexdigest()

В противном случае вы получите:

Traceback (последний последний звонок):
  Файл "", строка 1, на
    hashed_password = hashlib.sha512 (пароль + соль).hexdigest()
TypeError: Unicode-объекты должны быть закодированы перед хэшированием

Ответ 5

passlib представляется полезным, если вам нужно использовать хеши, хранящиеся в существующей системе. Если у вас есть контроль над форматом, используйте современный хэш, например, bcrypt или scrypt. В настоящее время bcrypt, по-видимому, намного проще использовать из python.

passlib поддерживает bcrypt и рекомендует устанавливать py-bcrypt в качестве бэкэнд: http://pythonhosted.org/passlib/lib/passlib.hash.bcrypt.html

Вы также можете использовать py-bcrypt, если вы не хотите устанавливать passlib. В readme есть примеры базового использования.

см. также: Как использовать scrypt для генерации хэша для пароля и соли в Python

Ответ 6

Я не хочу воскрешать старую ветку, но... любой, кто хочет использовать современное и безопасное решение, использует argon2.

https://pypi.python.org/pypi/argon2_cffi

Он выиграл конкурс хэширования паролей. (https://password-hashing.net/) Его проще использовать, чем bcrypt, и он более безопасен, чем bcrypt.

Ответ 7

Начиная с Python 3.4, модуль hashlib в стандартной библиотеке содержит функции получения ключей, которые "предназначены для безопасного хеширования паролей".

Так что используйте один из них, например hashlib.pbkdf2_hmac, с солью, сгенерированной с использованием os.urandom:

from typing import Tuple
import os
import hashlib
import hmac

def hash_new_password(password: str) -> Tuple[bytes, bytes]:
    """
    Hash the provided password with a randomly-generated salt and return the
    salt and hash to store in the database.
    """
    salt = os.urandom(16)
    pw_hash = hashlib.pbkdf2_hmac('sha256', password.encode(), salt, 100000)
    return salt, pw_hash

def is_correct_password(salt: bytes, pw_hash: bytes, password: str) -> bool:
    """
    Given a previously-stored salt and hash, and a password provided by a user
    trying to log in, check whether the password is correct.
    """
    return hmac.compare_digest(
        pw_hash,
        hashlib.pbkdf2_hmac('sha256', password.encode(), salt, 100000)
    )

# Example usage:
salt, pw_hash = hash_new_password('correct horse battery staple')
assert is_correct_password(salt, pw_hash, 'correct horse battery staple')
assert not is_correct_password(salt, pw_hash, 'Tr0ub4dor&3')
assert not is_correct_password(salt, pw_hash, 'rosebud')

Обратите внимание, что:

  • Использование 16-байтовой соли и 100000 итераций PBKDF2 соответствует минимальным числам, рекомендованным в документации по Python. Дальнейшее увеличение числа итераций замедлит вычисление ваших хэшей и, следовательно, сделает их более безопасными.
  • os.urandom всегда использует криптографически безопасный источник случайности
  • hmac.compare_digest, используемый в is_correct_password, в основном является просто оператором == для строк, но без возможности короткого замыкания, что делает его невосприимчивым к временным атакам. Это, вероятно, на самом деле не дает никакого дополнительного значения безопасности, но это также не повредит, поэтому я пошел дальше и использовал его.

Теорию о том, что делает хороший хеш паролей и список других функций, подходящих для хеширования паролей, см. По адресу https://security.stackexchange.com/q/211/29805.

Ответ 8

Во-первых, импорт: -

import hashlib, uuid

Затем измените ваш код в соответствии с этим в вашем методе:

uname = request.form["uname"]
pwd=request.form["pwd"]
salt = hashlib.md5(pwd.encode())

Затем передайте эту соль и uname в вашем sql-запросе к базе данных, под логином указано имя таблицы:

sql = "insert into login values ('"+uname+"','"+email+"','"+salt.hexdigest()+"')"