Python-Programmierer/innen verwenden Hashing, um Eingabedaten in einen Wert fester Größe umzuwandeln. Dieser Wert repräsentiert die Daten eindeutig, und die Hash-Technik macht es einfach, verschiedene Formen von Daten sicher zu übertragen und zu speichern.

Hashing schützt Daten vor unberechtigtem Zugriff und Manipulation. Es ist ein wesentlicher Bestandteil der Datenintegrität und der Sicherheit von Anwendungsfällen.

In diesem Artikel erfährst du alles, was du über Hashing in Python wissen musst. Er geht auf die Einsatzmöglichkeiten von Hashing ein und stellt verschiedene Hashing-Algorithmen vor, die deinen Code effizienter, sicherer und zuverlässiger machen.

Was ist Hashing in Python?

Beim Hashing werden Eingabedaten, wie z. B. eine Zeichenkette, eine Datei oder ein Objekt, in eine Zeichenkette mit fester Größe umgewandelt. Der Hash oder Digest repräsentiert die Eingabe auf eindeutige und reproduzierbare Weise.

Hashing spielt eine wichtige Rolle bei der Erkennung von Datenmanipulationen und der Verbesserung der Sicherheit. Es kann einen Hash-Wert für eine Datei, eine Nachricht oder ein anderes Datenelement errechnen. Eine Anwendung speichert den Hashwert sicher, um später zu überprüfen, ob die Daten nicht manipuliert wurden.

Eine der häufigsten Anwendungen von Hashing im Sicherheitsbereich ist die Speicherung von Passwörtern. Hashing ist eine praktikable Alternative zur Speicherung von Klartextpasswörtern in einer Datenbank. Wenn ein Benutzer sein Passwort eingibt, wird es vom System gehasht, bevor es in der Datenbank gespeichert wird. Wenn ein Hacker auf die Datenbank zugreift, wird er feststellen, dass das Passwort nur schwer zu stehlen ist.

Die Hashing-Funktionen von Python machen all dies möglich. Mit diesen mathematischen Funktionen kann eine Anwendung Daten in Hash-Werte umwandeln.

Wie man eine wirksame Hashing-Funktion erstellt

Eine Hashing-Funktion sollte die folgenden Kriterien erfüllen, um effektiv und sicher zu sein:

  • Deterministisch – Bei gleicher Eingabe sollte die Funktion immer die gleiche Ausgabe liefern.
  • Effizient – Sie sollte bei der Berechnung des Hashwerts einer beliebigen Eingabe rechnerisch effizient sein.
  • Kollisionssicher – Die Funktion sollte die Wahrscheinlichkeit minimieren, dass zwei Eingaben denselben Hash-Wert ergeben.
  • Gleichmäßig – Die Ausgaben der Funktion sollten gleichmäßig über den Bereich der möglichen Hash-Werte verteilt sein.
  • Nicht umkehrbar – Es sollte unwahrscheinlich sein, dass ein Computer den Eingabewert der Funktion auf der Grundlage des Hashwerts berechnen kann.
  • Nicht vorhersehbar – Es sollte schwierig sein, die Ergebnisse der Funktion aus einer Reihe von Eingaben vorherzusagen.
  • Empfindlich gegenüber Änderungen der Eingaben – Die Funktion sollte empfindlich gegenüber kleinen Unterschieden in der Eingabe sein. Geringe Änderungen sollten einen großen Unterschied im resultierenden Hash-Wert bewirken.

Hashing Use Cases

Sobald du eine geeignete Hash-Funktion mit all diesen Eigenschaften hast, kannst du sie für verschiedene Anwendungsfälle einsetzen. Hashing-Funktionen eignen sich gut für:

  • Speicherung von Passwörtern – Hashing ist eine der besten Methoden, um Benutzerpasswörter in modernen Systemen zu speichern. Python kombiniert verschiedene Module, um Passwörter zu hashen und zu sichern, bevor sie in einer Datenbank gespeichert werden.
  • Zwischenspeichern – Hashing speichert die Ausgabe einer Funktion, um Zeit zu sparen, wenn sie später aufgerufen wird.
  • Datenabfrage – Python verwendet eine Hash-Tabelle mit einer eingebauten Wörterbuch-Datenstruktur, um Werte schnell nach Schlüssel abzurufen.
  • Digitale Signaturen – Hashing kann die Authentizität von Nachrichten mit digitalen Signaturen überprüfen.
  • Überprüfung der Dateiintegrität – Hashing kann die Integrität einer Datei während der Übertragung und des Downloads überprüfen.

Pythons eingebaute Hashing-Funktion

Die in Python eingebaute Hash-Funktion hash() gibt einen ganzzahligen Wert zurück, der das Eingabeobjekt darstellt. Der Code verwendet dann den resultierenden Hash-Wert, um die Position des Objekts in der Hashtabelle zu bestimmen. Diese Hash-Tabelle ist eine Datenstruktur, die Wörterbücher und Mengen implementiert.

Der folgende Code zeigt, wie die Funktion hash() funktioniert:

my_string = "hello world"

# Calculate the hash value of the string
hash_value = hash(my_string)

# Print the string and its hash value
print("String: ", my_string)
print("Hash value: ", hash_value)

Wenn wir diesen Code in einer Datei namens hash.py speichern, können wir ihn wie folgt ausführen (und die Ausgabe sehen):

% python3 hash.py
String:  hello world
Hash value:  2213812294562653681

Lass uns das noch einmal ausführen:

% python3 hash.py
String:  hello world
Hash value:  -631897764808734609

Der Hash-Wert ist anders, wenn er ein zweites Mal aufgerufen wird, weil neuere Versionen von Python (ab Version 3.3) standardmäßig einen zufälligen Hash-Seed für diese Funktion verwenden. Der Seed ändert sich bei jedem Aufruf von Python. Innerhalb einer einzelnen Instanz werden die Ergebnisse identisch sein.

Fügen wir zum Beispiel diesen Code in unsere Datei hash.py ein:

my_string = "hello world"

# Calculate 2 hash values of the string
hash_value1 = hash(my_string)
hash_value2 = hash(my_string)

# Print the string and its hash values
print("String: ", my_string)
print("Hash value 1: ", hash_value1)
print("Hash value 2: ", hash_value2)

Wenn er ausgeführt wird, sehen wir etwas wie das hier:

String: hello world
Hash value 1:  -7779434013116951864
Hash value 2:  -7779434013116951864

Beschränkungen des Hashings

Obwohl die Hash-Funktion von Python für verschiedene Anwendungsfälle vielversprechend ist, ist sie aufgrund ihrer Einschränkungen für Sicherheitszwecke nicht geeignet. So geht’s:

  • Kollisionsangriffe – Eine Kollision liegt vor, wenn zwei verschiedene Eingaben denselben Hash-Wert ergeben. Ein Angreifer könnte dieselbe Eingabemethode verwenden, um Sicherheitsmaßnahmen zu umgehen, die sich auf Hash-Werte zur Authentifizierung oder Datenintegritätsprüfung stützen.
  • Begrenzte Eingabegröße – Da Hash-Funktionen unabhängig von der Größe der Eingabe eine Ausgabe mit fester Größe erzeugen, kann eine Eingabe, die größer als die Ausgabe der Hash-Funktion ist, eine Kollision verursachen.
  • Vorhersagbarkeit – Eine Hash-Funktion sollte deterministisch sein, d. h. sie sollte jedes Mal dieselbe Ausgabe liefern, wenn du dieselbe Eingabe machst. Angreifer können diese Schwäche ausnutzen, indem sie Hash-Werte für viele Eingaben vorkompilieren und sie dann mit den Hash-Werten der Zielwerte vergleichen, um eine Übereinstimmung zu finden. Dieser Vorgang wird als Rainbow-Table-Angriff bezeichnet.

Um Angriffe zu verhindern und deine Daten zu schützen, solltest du sichere Hash-Algorithmen verwenden, die gegen solche Schwachstellen geschützt sind.

Hashlib für sicheres Hashing in Python verwenden

Anstatt das eingebaute Python hash() zu verwenden, kannst du hashlib für sicheres Hashing nutzen. Dieses Python-Modul bietet eine Vielzahl von Hash-Algorithmen, um Daten sicher zu hashen. Zu diesen Algorithmen gehören MD5, SHA-1 und die sicherere SHA-2-Familie, einschließlich SHA-256, SHA-384, SHA-512 und andere.

MD5

Der weit verbreitete kryptografische Algorithmus MD5 gibt einen 128-Bit-Hashwert preis. Verwende den folgenden Code, um mit dem Konstruktor md5 der hashlib einen MD5-Hashwert zu erzeugen:

import hashlib

text = "Hello World"
hash_object = hashlib.md5(text.encode())
print(hash_object.hexdigest())

Die Ausgabe des obigen Codes (in unserer Datei hash.py) wird bei allen Aufrufen gleich sein:

b10a8db164e0754105b7a99be72e3fe5

Hinweis: Die Methode hexdigest() im obigen Code gibt den Hash in einem hexadezimalen Format zurück, das für alle nicht-binären Darstellungen (z. B. E-Mail) geeignet ist.

SHA-1

Die Hash-Funktion SHA-1 sichert Daten, indem sie einen 160-Bit-Hash-Wert erzeugt. Verwende den folgenden Code mit dem sha1 Konstruktor für den SHA-1 Hash des hashlib-Moduls:

import hashlib

text = "Hello World"
hash_object = hashlib.sha1(text.encode())
print(hash_object.hexdigest())

Die Ausgabe des obigen Beispiels:

0a4d55a8d778e5022fab701977c5d840bbc486d0

SHA-256

Es gibt verschiedene Hash-Optionen in der SHA-2 Familie. Der Konstruktor hashlib SHA-256 erzeugt eine sicherere Version dieser Familie mit einem 256-Bit-Hashwert.

Programmierer verwenden SHA-256 oft für kryptografische Zwecke, wie digitale Signaturen oder Authentifizierungscodes für Nachrichten. Der folgende Code zeigt, wie man einen SHA-256-Hashwert erzeugt:

import hashlib

text = "Hello World"
hash_object = hashlib.sha256(text.encode())
print(hash_object.hexdigest())

Die Ausgabe des obigen Codes:

a591a6d40bf420404a011733cfb7b190d62c65bf0bcda32b57b277d9ad9f146e

SHA-384

SHA-384 ist ein 384-Bit-Hash-Wert. Programmierer verwenden die SHA-384-Funktion oft in Anwendungen, die mehr Datensicherheit benötigen.

Anhand der vorherigen Beispiele kannst du wahrscheinlich erraten, dass dies eine Anweisung ist, die einen SHA-384-Hashwert erzeugt:

hash_object = hashlib.sha384(text.encode())

SHA-512

SHA-512 ist das sicherste Mitglied der SHA-2 Familie. Es erzeugt einen 512-Bit-Hashwert. Programmierer verwenden es für Anwendungen mit hohem Durchsatz, z. B. zur Überprüfung der Datenintegrität. Der folgende Code zeigt, wie man einen SHA-512-Hash mit dem hashlib-Modul in Python erzeugt:

hash_object = hashlib.sha512(text.encode())

Wie man einen Hash-Algorithmus auswählt

Da sich diese Algorithmen unterscheiden, solltest du deinen Hash-Algorithmus anhand deines Anwendungsfalls und seiner Sicherheitsanforderungen auswählen. Hier sind einige Schritte, die du befolgen solltest:

  • Verstehe den Anwendungsfall – Dein Anwendungsfall bestimmt, welche Art von Algorithmus du verwenden solltest. Wenn du zum Beispiel sensible Daten wie Passwörter speicherst, sollte dein Hashing-Algorithmus vor Brute-Force-Angriffen schützen.
  • Berücksichtige deine Sicherheitsanforderungen – Die Sicherheitsanforderungen deines Anwendungsfalls hängen von der Art der zu speichernden Daten ab und bestimmen, welche Art von Algorithmus du wählen solltest. Ein robuster Hashing-Algorithmus eignet sich zum Beispiel am besten für die Speicherung hochsensibler Daten.
  • Recherchiere die verfügbaren Hash-Algorithmen – Untersuche jeden Hash-Typ, um seine Stärken und Schwächen zu verstehen. Diese Informationen helfen dir, die beste Option für deinen Anwendungsfall auszuwählen.
  • Evaluiere den gewählten Hash-Algorithmus – Sobald du dich für einen Hash-Algorithmus entschieden hast, musst du prüfen, ob er deinen Sicherheitsanforderungen entspricht. Dazu kann es notwendig sein, ihn gegen bekannte Angriffe oder Schwachstellen zu testen.
  • Implementiere und teste den Hash-Algorithmus – Schließlich implementiere und teste den Algorithmus gründlich, um sicherzustellen, dass er korrekt und sicher funktioniert.

Wie man Hashing für die Passwortspeicherung nutzt

Hashing eignet sich hervorragend für die Speicherung von Passwörtern, einer wichtigen Komponente der Cybersicherheit.

Im Idealfall hasht und speichert die Anwendung Passwörter in einer sicheren Datenbank, um unbefugten Zugriff und Datenmissbrauch zu verhindern. Das Hashing allein reicht jedoch nicht aus, um die Informationen zu schützen. Gehashte Passwörter sind immer noch anfällig für Brute-Force- und Wörterbuchangriffe. Hacker nutzen diese Methoden häufig, um Passwörter zu erraten und sich unbefugten Zugang zu Konten zu verschaffen.

Eine sicherere Methode, Hashing für die Passwortspeicherung zu verwenden, ist die Salting-Technik. Beim Salting werden jedem Passwort einzigartige, zufällige Zeichenfolgen oder Zeichen hinzugefügt, bevor es gehasht wird. Das Salt ist für jedes Passwort einzigartig und wird von der Anwendung zusammen mit dem gehashten Passwort in der Datenbank gespeichert.

Jedes Mal, wenn sich ein Benutzer anmeldet, ruft die Anwendung das Salt aus der Datenbank ab, fügt es dem eingegebenen Passwort hinzu und verschlüsselt dann das kombinierte Salt und Passwort.

Wenn sich ein Angreifer Zugang zur Datenbank verschafft, muss er den Hash für jedes Passwort und jeden möglichen Salt-Wert berechnen. Das Salzen macht diese Angriffe komplexer und ist daher eine hilfreiche Technik, um Wörterbuchangriffe abzuwehren.

Das secrets Modul von Python macht das Salting einfach. Dieses Modul erzeugt zufällige Salts, speichert Passwörter sicher und verwaltet Token und kryptografische Schlüssel.

Der folgende Code nutzt die hashlib-Bibliothek und das secrets-Modul, um die Passwörter der Nutzer noch besser zu schützen:

import hashlib
import secrets

# Generate a random salt using the secrets module
salt = secrets.token_hex(16)

# Get the user's password from input
password = input("Enter your password: ")

# Hash the password using the salt and the SHA-256 algorithm
hash_object = hashlib.sha256((password + salt).encode())

# Get the hexadecimal representation of the hash
hash_hex = hash_object.hexdigest()

# Store the salt and hash_hex in your database

Wie man Hashing für Datenintegritätsprüfungen verwendet

Hashing hilft auch dabei, die Integrität von Daten zu prüfen und übertragene Daten vor Veränderungen und Manipulationen zu schützen. Diese vierstufige Technik verwendet eine kryptografische Hash-Funktion, um der Datei einen eindeutigen Hash-Wert zu geben.

Zunächst wählst du eine geeignete Hash-Funktion aus und erzeugst mit ihr einen Hash-Wert für die Eingabedaten. Speichere diesen Hash-Wert und verwende ihn bei Bedarf zum Vergleich. Wann immer du die Integrität der Daten überprüfen musst, erzeugt die Anwendung den Hash-Wert der aktuellen Daten mit derselben Hash-Funktion. Dann vergleicht die Anwendung den neuen Hashwert mit dem gespeicherten Wert, um sicherzustellen, dass sie identisch sind. Ist dies der Fall, sind die Daten unbeschädigt.

Der Hashwert ist eindeutig, und selbst eine winzige Änderung der Eingabedaten führt zu einem deutlich anderen Hashwert. So lassen sich unbefugte Änderungen an den übermittelten Daten leicht erkennen.

Die folgenden Schritte veranschaulichen die Verwendung einer Hash-Funktion zur Überprüfung der Datenintegrität.

Schritt 1: Importiere das hashlib-Modul

import hashlib

Schritt 2: Einen hashlib-Hash-Algorithmus verwenden

def generate_hash(file_path):

    # Open the file in binary mode
    with open(file_path, "rb") as f:

        # Read the contents of the file
        contents = f.read()

        # Generate the SHA-256 hash of the contents
        hash_object = hashlib.sha256(contents)

        # Return the hexadecimal representation of the hash
        return hash_object.hexdigest()

Schritt 3: Rufe die Funktion auf und gib den Dateipfad an

file_path = "path/to/my/file.txt"
hash_value = generate_hash(file_path)
print(hash_value)

Schritt 4: Erzeuge Hashes für die Originaldatei und die übertragene oder geänderte Datei

# Generate the hash of the original file
original_file_path = "path/to/my/file.txt"
original_file_hash = generate_hash(original_file_path)

# Transmit or modify the file (for example, by copying it to a different location)
transmitted_file_path = "path/to/transmitted/file.txt"

# Generate the hash of the transmitted file
transmitted_file_hash = generate_hash(transmitted_file_path)

Schritt 5: Vergleich der beiden Hashes

if original_file_hash == transmitted_file_hash:
    print("The file has not been tampered with")
else:
    print("The file has been tampered with")

Zusammenfassung

Hashing ist von unschätzbarem Wert für die Datenintegrität und die Passwortsicherheit. Du holst das Beste aus einer Hash-Funktion heraus, wenn du sichere Hash-Techniken einsetzt, z. B. das hashlib-Modul und Salting.

Diese Techniken helfen dabei, Regenbogenangriffe, Kollisionsangriffe und andere Sicherheitslücken zu verhindern, die das Hashing betreffen. Programmierer nutzen diese Techniken oft mit Hashing-Funktionen in Python, um die Datenintegrität von Dateien zu gewährleisten und Passwörter sicher zu speichern.

Jetzt, wo du mehr über Hashing-Techniken in Python erfahren hast, kannst du sie nutzen, um die Sicherheit deiner eigenen Anwendung zu verbessern. Lies weitere Python-Artikel im Kinsta-Blog, um dein Wissen zu erweitern, und überlege, ob du deine nächste Python-Anwendung auf der Anwendungs-Hosting-Plattform von Kinsta bereitstellst.

Steve Bonisteel

Kinsta

Steve Bonisteel is a Technical Editor at Kinsta who began his writing career as a print journalist, chasing ambulances and fire trucks. He has been covering Internet-related technology since the late 1990s.