Esse código deve criar um hash de uma senha com um salt. A senha salt e hash estão sendo salvas no banco de dados. A senha em si não é.
Dada a natureza delicada da operação, eu queria ter certeza de que tudo era kosher.
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())
t_sha.digest() + salt
. Você pode dividir o salt novamente mais tarde, quando tiver decodificado a senha hash salted, pois você sabe que a senha hash decodificada tem exatamente 32 bytes.secrets
lugar.Respostas:
EDIT: Esta resposta está errada. Uma única iteração do SHA512 é rápida , o que o torna impróprio para uso como função de hash de senha. Use uma das outras respostas aqui.
Parece bom para mim. No entanto, tenho certeza de que você não precisa de base64. Você poderia apenas fazer isso:
import hashlib, uuid salt = uuid.uuid4().hex hashed_password = hashlib.sha512(password + salt).hexdigest()
Se isso não criar dificuldades, você pode obter um armazenamento um pouco mais eficiente em seu banco de dados, armazenando a senha salt e hash como bytes brutos em vez de strings hexadecimais. Para fazer isso, substitua
hex
porbytes
ehexdigest
pordigest
.fonte
salt
está armazenado no banco de dados e a senha com hash salgada também.Com base nas outras respostas a esta pergunta, implementei uma nova abordagem usando bcrypt.
Por que usar bcrypt
Se bem entendi, o argumento para usar
bcrypt
maisSHA512
é quebcrypt
é projetado para ser lento.bcrypt
também tem uma opção para ajustar a lentidão que você deseja ao gerar a senha com hash pela primeira vez:# The '12' is the number that dictates the 'slowness' bcrypt.hashpw(password, bcrypt.gensalt( 12 ))
Devagar é desejável porque se uma parte mal-intencionada colocar as mãos na mesa que contém senhas com hash, será muito mais difícil aplicá-las à força bruta.
Implementação
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)
Notas
Consegui instalar a biblioteca facilmente em um sistema Linux usando:
No entanto, tive mais problemas para instalá-lo em meus sistemas Windows. Parece que precisa de um patch. Veja esta pergunta do Stack Overflow: py-bcrypt instalando no win 7 64bit python
fonte
py-bcrypt
é o antigo pacote pypi e desde então foi renomeado parabcrypt
.O mais inteligente não é escrever a criptografia você mesmo, mas usar algo como passlib: https://bitbucket.org/ecollins/passlib/wiki/Home
É fácil bagunçar escrevendo seu código criptográfico de maneira segura. O desagradável é que, com código não criptografado, você geralmente percebe imediatamente quando não está funcionando, pois o programa trava. Enquanto com o código criptográfico, muitas vezes você só descobre depois que é tarde demais e seus dados foram comprometidos. Portanto, acho melhor usar um pacote escrito por alguém que tenha conhecimento sobre o assunto e que seja baseado em protocolos testados em batalha.
Além disso, passlib tem alguns recursos interessantes que o tornam fácil de usar e também de atualizar para um protocolo de hash de senha mais recente, se um protocolo antigo for quebrado.
Além disso, apenas uma única rodada de sha512 é mais vulnerável a ataques de dicionário. O sha512 foi projetado para ser rápido e isso é realmente uma coisa ruim ao tentar armazenar senhas com segurança. Outras pessoas têm pensado muito sobre todos esses problemas, então é melhor você tirar vantagem disso.
fonte
hashlib
é para funções de hash criptográficas.passlib
serve para armazenar senhas com segurança. Eles não são a mesma coisa (embora muitas pessoas pareçam pensar assim .. e então suas senhas de usuários são quebradas).passlib
gera seu próprio salt, que é armazenado na string hash retornada (pelo menos para certos esquemas como BCrypt + SHA256 ) - então você não precisa se preocupar com isso.Para que isso funcione no Python 3, você precisará codificar UTF-8, por exemplo:
hashed_password = hashlib.sha512(password.encode('utf-8') + salt.encode('utf-8')).hexdigest()
Caso contrário, você obterá:
fonte
A partir do Python 3.4, o
hashlib
módulo na biblioteca padrão contém funções de derivação chave que são "projetadas para hashing de senha seguro" .Portanto, use um desses, como
hashlib.pbkdf2_hmac
, com um sal gerado usandoos.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')
Observe que:
os.urandom
sempre usa uma fonte criptograficamente segura de aleatoriedadehmac.compare_digest
, usado emis_correct_password
, é basicamente apenas o==
operador para strings, mas sem a capacidade de curto-circuito, o que o torna imune a ataques de temporização. Isso provavelmente não fornece nenhum valor de segurança extra , mas também não faz mal nenhum, então fui em frente e usei isso.Para ver a teoria sobre o que torna um bom hash de senha e uma lista de outras funções apropriadas para fazer hash de senhas, consulte https://security.stackexchange.com/q/211/29805 .
fonte
passlib parece ser útil se você precisar usar hashes armazenados por um sistema existente. Se você tiver controle do formato, use um hash moderno como bcrypt ou scrypt. No momento, o bcrypt parece ser muito mais fácil de usar no python.
passlib suporta bcrypt e recomenda a instalação de py-bcrypt como back-end: http://pythonhosted.org/passlib/lib/passlib.hash.bcrypt.html
Você também pode usar o py-bcrypt diretamente se não quiser instalar o passlib. O leia-me contém exemplos de uso básico.
veja também: Como usar scrypt para gerar hash para senha e salt em Python
fonte
Eu não quero ressuscitar um tópico antigo, mas ... qualquer um que quiser usar uma solução segura moderna e atualizada, use o argon2.
https://pypi.python.org/pypi/argon2_cffi
Ele venceu a competição de hashing de senha. ( https://password-hashing.net/ ) É mais fácil de usar que bcrypt e é mais seguro que bcrypt.
fonte
Primeiramente importe: -
import hashlib, uuid
Em seguida, altere seu código de acordo com o seguinte em seu método:
uname = request.form["uname"] pwd=request.form["pwd"] salt = hashlib.md5(pwd.encode())
Em seguida, passe este salt e uname em sua consulta sql de banco de dados, abaixo de login está um nome de tabela:
sql = "insert into login values ('"+uname+"','"+email+"','"+salt.hexdigest()+"')"
fonte