it-swarm.com.de

Salt und Hash ein Passwort in python

Dieser Code soll ein Passwort mit einem Salt haben. Das Salt- und das Hash-Passwort werden in der Datenbank gespeichert. Das Passwort selbst ist nicht.

Angesichts der Sensibilität der Operation wollte ich sicherstellen, dass alles koscher ist.

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())
73
Chris Dutrow

EDIT: Diese Antwort ist falsch. Eine einzelne Iteration von SHA512 ist schnell , was die Verwendung als Passwort-Hash-Funktion unangemessen macht. Verwenden Sie stattdessen eine der anderen Antworten.


Sieht gut aus von mir. Ich bin mir jedoch ziemlich sicher, dass Sie base64 nicht wirklich brauchen. Sie könnten dies einfach tun:

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

Wenn dies keine Probleme verursacht, können Sie den Speicher in Ihrer Datenbank etwas effizienter gestalten, indem Sie das Salt- und das Hash-Kennwort als unformatierte Bytes und nicht als hexadezimale Zeichenfolgen speichern. Ersetzen Sie dazu hex durch bytes und hexdigest durch digest.

38
Taymon

Basierend auf den anderen Antworten auf diese Frage habe ich einen neuen Ansatz mit bcrypt implementiert.

Warum sollte man bcrypt benutzen?

Wenn ich richtig verstehe, wird das Argument bcrypt über SHA512 ist, dass bcrypt langsam ist. bcrypt hat auch eine Option zum Anpassen, wie langsam es sein soll, wenn das gehashte Passwort zum ersten Mal generiert wird:

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

Langsam ist wünschenswert, denn wenn eine böswillige Partei den Tisch mit den gehackten Passwörtern in die Hände bekommt, ist es viel schwieriger, sie zu erzwingen.

Implementierung

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)

Anmerkungen

Ich konnte die Bibliothek ziemlich einfach in einem Linux-System installieren, indem ich folgendes verwendete:

pip install py-bcrypt

Ich hatte jedoch größere Probleme bei der Installation auf meinen Windows-Systemen. Es scheint einen Patch zu brauchen. Siehe diese Frage zum Stapelüberlauf: Installation von py-bcrypt auf Win 7 64-Bit-Python

50
Chris Dutrow

Das Schlaue ist nicht, die Krypto selbst zu schreiben, sondern so etwas wie passlib zu verwenden: https://bitbucket.org/ecollins/passlib/wiki/Home

Es ist einfach, das Schreiben Ihres Krypto-Codes auf sichere Weise durcheinander zu bringen. Das Schlimme ist, dass Sie bei Nicht-Krypto-Code oft sofort bemerken, dass er nicht funktioniert, da Ihr Programm abstürzt. Während mit Krypto-Code Sie oft erst herausfinden, wenn es zu spät ist und Ihre Daten kompromittiert wurden. Aus diesem Grund halte ich es für besser, ein Paket zu verwenden, das von jemand anderem geschrieben wurde, der sich mit dem Thema auskennt und auf kampferprobten Protokollen basiert.

Passlib hat auch einige nette Funktionen, die es einfach machen, es zu benutzen und auf ein neueres Passwort-Hashing-Protokoll zu aktualisieren, wenn sich herausstellt, dass ein altes Protokoll kaputt ist.

Außerdem ist nur eine Runde sha512 anfälliger für Wörterbuchangriffe. sha512 ist so konzipiert, dass es schnell ist, und dies ist eigentlich eine schlechte Sache, wenn Passwörter sicher gespeichert werden sollen. Andere Leute haben lange und gründlich über diese Art von Problemen nachgedacht, damit Sie diese Vorteile besser nutzen können.

46
M.D.

Damit dies in Python 3 funktioniert, müssen Sie UTF-8 codieren, zum Beispiel:

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

Sonst bekommst du:

Rückverfolgung (letzter Anruf zuletzt):
Datei "", Zeile 1, in
hashed_password = hashlib.sha512 (Passwort + Salt) .hexdigest ()
TypeError: Unicode-Objekte müssen vor dem Hashing codiert werden

18
Wayne

passlib scheint nützlich zu sein, wenn Sie von einem vorhandenen System gespeicherte Hashes verwenden müssen. Wenn Sie das Format steuern können, verwenden Sie einen modernen Hash wie bcrypt oder scrypt. Gegenwärtig scheint es viel einfacher zu sein, bcrypt mit Python zu verwenden.

passlib unterstützt bcrypt und empfiehlt, py-bcrypt als Backend zu installieren: http://pythonhosted.org/passlib/lib/passlib.hash.bcrypt.html

Sie können auch py-bcrypt direkt verwenden, wenn Sie die passlib nicht installieren möchten. Die Readme-Datei enthält Beispiele für die grundlegende Verwendung.

siehe auch: Verwendung von Scrypt zum Generieren von Hash für Passwort und Salt in Python

10
Terrel Shumway

Ich möchte keinen alten Thread wiederbeleben, aber ... wer eine moderne und sichere Lösung verwenden möchte, verwendet argon2.

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

Es hat den Passwort-Hashing-Wettbewerb gewonnen. ( https://password-hashing.net/ ) Es ist einfacher zu verwenden als bcrypt und sicherer als bcrypt.

6
nagylzs

Erstens importieren: -

import hashlib, uuid

Dann ändern Sie Ihren Code wie folgt in Ihrer Methode:

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

Übergeben Sie dann dieses Salt und Uname in Ihrer Datenbank-SQL-Abfrage. Unter login befindet sich ein Tabellenname:

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

Ab Python 3.4 enthält das Modul hashlib in der Standardbibliothek Schlüsselableitung Funktionen, die "entworfen wurden für sicheres Passwort-Hashing ".

Verwenden Sie also eines davon, wie hashlib.pbkdf2_hmac , mit einem Salz, das mit 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')

Beachten Sie, dass:

  • Die Verwendung eines 16-Byte-Salt und 100000 Iterationen von PBKDF2 entsprechen den in den Python docs empfohlenen Mindestzahlen. Wenn Sie die Anzahl der Iterationen weiter erhöhen, werden Ihre Hashes langsamer und damit sicherer .
  • os.urandom verwendet immer eine kryptografisch sichere Zufallsquelle
  • hmac.compare_digest , verwendet in is_correct_password, ist im Grunde nur die == Operator für Saiten, aber ohne die Fähigkeit, kurzzuschließen, was es immun gegen Timing-Attacken macht. Das bietet wahrscheinlich keinen zusätzlichen Sicherheitswert , aber es tut auch nicht weh, also habe ich es benutzt.

Eine Theorie darüber, was einen guten Passwort-Hash ausmacht, und eine Liste anderer Funktionen, mit denen Passwörter gehasht werden können, finden Sie unter https://security.stackexchange.com/q/211/29805 .

0
Mark Amery