Ten kod ma zhaszować hasło za pomocą soli. Sól i zaszyfrowane hasło są zapisywane w bazie danych. Samo hasło nie jest.
Biorąc pod uwagę delikatny charakter operacji, chciałem się upewnić, że wszystko jest koszerne.
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
. Możesz ponownie podzielić sól później, gdy odkodujesz solone hasło mieszające, ponieważ wiesz, że zdekodowane zaszyfrowane hasło ma dokładnie 32 bajty.secrets
.Odpowiedzi:
EDYCJA: ta odpowiedź jest błędna. Pojedyncza iteracja SHA512 jest szybka , co sprawia, że nie nadaje się do użycia jako funkcja mieszania haseł. Zamiast tego użyj jednej z pozostałych odpowiedzi.
Według mnie wygląda dobrze. Jednak jestem prawie pewien, że tak naprawdę nie potrzebujesz base64. Możesz po prostu zrobić to:
import hashlib, uuid salt = uuid.uuid4().hex hashed_password = hashlib.sha512(password + salt).hexdigest()
Jeśli nie powoduje to trudności, możesz uzyskać nieco bardziej wydajne przechowywanie w bazie danych, przechowując sól i zaszyfrowane hasło jako surowe bajty, a nie ciągi szesnastkowe. Aby to zrobić, należy wymienić
hex
zbytes
ihexdigest
zdigest
.źródło
salt
są przechowywane w bazie danych, a także zaszyfrowane hasło.Na podstawie innych odpowiedzi na to pytanie zaimplementowałem nowe podejście przy użyciu bcrypt.
Dlaczego warto korzystać z bcrypt
Jeśli dobrze rozumiem, argument użyć
bcrypt
naSHA512
to, żebcrypt
ma być powolny.bcrypt
ma również opcję dostosowania, jak wolno ma być generowane zaszyfrowane hasło po raz pierwszy:# The '12' is the number that dictates the 'slowness' bcrypt.hashpw(password, bcrypt.gensalt( 12 ))
Powolne jest pożądane, ponieważ jeśli złośliwa strona dostanie ręce na stół zawierający zaszyfrowane hasła, znacznie trudniej jest je brutalnie wymusić.
Realizacja
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)
Uwagi
Udało mi się dość łatwo zainstalować bibliotekę w systemie Linux przy użyciu:
Jednak miałem więcej problemów z instalacją go w moich systemach Windows. Wydaje się, że potrzebuje poprawki. Zobacz to pytanie o przepełnienie stosu: instalacja py-bcrypt na win 7 64-bitowym pythonie
źródło
py-bcrypt
to, że jest to stary pakiet pypi i od tego czasu jego nazwa została zmieniona nabcrypt
.Mądrą rzeczą nie jest samodzielne pisanie krypto, ale użycie czegoś takiego jak passlib: https://bitbucket.org/ecollins/passlib/wiki/Home
Łatwo jest zepsuć kod kryptograficzny w bezpieczny sposób. Paskudne jest to, że w przypadku kodu innego niż kryptograficzny często natychmiast zauważasz, że nie działa, ponieważ program się zawiesza. Podczas gdy z kodem kryptograficznym często dowiadujesz się, gdy jest już za późno, a Twoje dane zostały naruszone. Dlatego uważam, że lepiej jest użyć pakietu napisanego przez kogoś, kto ma wiedzę na ten temat i który jest oparty na protokołach przetestowanych w walce.
Passlib ma również kilka fajnych funkcji, które czynią go łatwym w użyciu, a także łatwą aktualizacją do nowszego protokołu haszowania haseł, jeśli stary protokół okaże się uszkodzony.
Również tylko jedna runda sha512 jest bardziej podatna na ataki słownikowe. sha512 został zaprojektowany tak, aby był szybki i jest to faktycznie zła rzecz, gdy próbuje się bezpiecznie przechowywać hasła. Inni ludzie długo i intensywnie zastanawiali się nad wszystkimi tego rodzaju sprawami, więc lepiej to wykorzystaj.
źródło
hashlib
służy do kryptograficznych funkcji skrótu.passlib
służy do bezpiecznego przechowywania haseł. To nie to samo (chociaż wydaje się, że wiele osób tak myśli ... a następnie hasła ich użytkowników są łamane).passlib
generuje własną sól, która jest przechowywana w zwróconym ciągu hash (przynajmniej dla niektórych schematów, takich jak BCrypt + SHA256 ) - więc nie musisz się tym martwić.Aby to zadziałało w Pythonie 3, musisz kodować UTF-8 na przykład:
hashed_password = hashlib.sha512(password.encode('utf-8') + salt.encode('utf-8')).hexdigest()
W przeciwnym razie otrzymasz:
źródło
Począwszy od Pythona 3.4,
hashlib
moduł w bibliotece standardowej zawiera funkcje wyprowadzania kluczy, które są „zaprojektowane do bezpiecznego mieszania haseł” .Więc użyj jednego z nich, na przykład
hashlib.pbkdf2_hmac
, z solą wygenerowaną przy użyciuos.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')
Zauważ, że:
os.urandom
zawsze używa kryptograficznie bezpiecznego źródła losowościhmac.compare_digest
, używany wis_correct_password
, jest w zasadzie tylko==
operatorem dla łańcuchów, ale bez możliwości zwarcia, co czyni go odpornym na ataki czasowe. To prawdopodobnie nie zapewnia żadnej dodatkowej wartości bezpieczeństwa , ale też nie boli, więc poszedłem do przodu i użyłem go.Aby poznać teorię na temat tego, co składa się na dobry skrót haseł i listę innych funkcji odpowiednich do haszowania haseł, zobacz https://security.stackexchange.com/q/211/29805 .
źródło
passlib wydaje się być przydatne, jeśli potrzebujesz użyć skrótów przechowywanych w istniejącym systemie. Jeśli masz kontrolę nad formatem, użyj nowoczesnego skrótu, takiego jak bcrypt lub scrypt. W tej chwili bcrypt wydaje się być znacznie łatwiejszy w użyciu z Pythona.
passlib obsługuje bcrypt i zaleca zainstalowanie py-bcrypt jako zaplecza: http://pythonhosted.org/passlib/lib/passlib.hash.bcrypt.html
Możesz także użyć bezpośrednio py-bcrypt, jeśli nie chcesz instalować passlib. Plik Readme zawiera przykłady podstawowego użycia.
zobacz także: Jak używać scrypt do generowania skrótu hasła i soli w Pythonie
źródło
Nie chcę wskrzeszać starego wątku, ale ... każdy, kto chce korzystać z nowoczesnego, bezpiecznego rozwiązania, powinien użyć argonu2.
https://pypi.python.org/pypi/argon2_cffi
Wygrał konkurs na mieszanie haseł. ( https://password-hashing.net/ ) Jest łatwiejszy w użyciu niż bcrypt i jest bezpieczniejszy niż bcrypt.
źródło
Po pierwsze importuj: -
import hashlib, uuid
Następnie zmień kod zgodnie z tym w swojej metodzie:
uname = request.form["uname"] pwd=request.form["pwd"] salt = hashlib.md5(pwd.encode())
Następnie podaj tę sól i uname w zapytaniu sql bazy danych, poniżej login jest nazwa tabeli:
sql = "insert into login values ('"+uname+"','"+email+"','"+salt.hexdigest()+"')"
źródło