Соль и хэш-пароль в Python - PullRequest
72 голосов
/ 07 марта 2012

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

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

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())

Ответы [ 8 ]

49 голосов
/ 20 мая 2014

Основываясь на других ответах на этот вопрос, я реализовал новый подход с использованием 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

45 голосов
/ 08 июня 2012

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

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

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

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

37 голосов
/ 07 марта 2012

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


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

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

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

18 голосов
/ 10 июня 2012

Чтобы это работало в 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-объекты должны быть закодированы перед хэшированием

9 голосов
/ 28 августа 2013

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 голосов
/ 14 августа 2017

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

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

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

0 голосов
/ 06 июля 2019

Начиная с 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.

0 голосов
/ 21 марта 2019

Сначала импортируйте: -

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()+"')"
...