Kryptografische Hash-Funktionen: Ein vollständiger Leitfaden
Kryptografische Hash-Funktionen sind die stillen Arbeitspferde der modernen Sicherheit. Jedes Mal, wenn Sie sich bei einer Website anmelden, Code zu Git pushen, eine Datei herunterladen oder eine Bitcoin-Transaktion durchführen, arbeiten Hash-Funktionen im Hintergrund. Dennoch interagieren die meisten Entwickler täglich mit ihnen, ohne wirklich zu verstehen, was sie tun — oder was schief gehen kann, wenn sie falsch verwendet werden.
Dieser Leitfaden deckt alles ab: die Mathematik, die Geschichte, die gebrochenen Algorithmen, die modernen Standards und den praktischen Code, den Sie benötigen, um Hash-Funktionen korrekt zu verwenden.
1. Was Sind Kryptografische Hash-Funktionen?
Eine kryptografische Hash-Funktion nimmt eine Eingabe beliebiger Größe und erzeugt eine Ausgabe fester Größe, den sogenannten Digest oder Hash-Wert. SHA-256 beispielsweise erzeugt immer genau 256 Bit (64 hexadezimale Zeichen), unabhängig davon, ob die Eingabe ein einzelnes Zeichen oder eine gesamte Filmdatei ist.
Grundlegende Eigenschaften
Deterministisch: Dieselbe Eingabe erzeugt immer dieselbe Ausgabe. SHA-256("hello") wird immer 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824 zurückgeben.
Schnell berechenbar: Die Berechnung eines Hash-Wertes sollte Millisekunden dauern. Diese Effizienz ist entscheidend für Dateiintegritätsprüfungen und digitale Signaturen, wird aber beim Passwort-Hashing zum Problem (dazu später mehr).
Einwegfunktion (Urbildresistenz): Gegeben ein Hash-Ausgabewert H, muss es rechnerisch unmöglich sein, eine Eingabe m zu finden, sodass hash(m) = H. Man kann aus dem Hash-Wert allein nicht auf die ursprünglichen Daten zurückschließen.
Zweite Urbildresistenz: Gegeben eine Eingabe m1, muss es unmöglich sein, eine andere Eingabe m2 zu finden, sodass hash(m1) = hash(m2). Selbst wenn ein Angreifer Ihre Originaldaten kennt, kann er keine andere Eingabe finden, die denselben Hash erzeugt.
Kollisionsresistenz: Es muss unmöglich sein, irgendein Paar unterschiedlicher Eingaben m1 und m2 zu finden, sodass hash(m1) = hash(m2). Dies ist eine stärkere Anforderung als die zweite Urbildresistenz.
Lawineneffekt: Eine winzige Änderung der Eingabe — selbst ein einzelnes Bit-Flip — verändert die Ausgabe vollständig. Die Änderung von "hello" zu "hellp" erzeugt einen völlig anderen Hash ohne erkennbare Beziehung zum Original.
SHA-256("hello") = 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
SHA-256("hellp") = 9b71d224bd62f3785d96d46ad3ea3d73319bfbc2890caadae2dff72519673ca7
Diese beiden Hash-Werte haben keine vorhersehbare Beziehung zueinander — das ist der Lawineneffekt in Aktion.
2. Kurze Geschichte der Hash-Algorithmen
MD5 (1991)
Ronald Rivest entwarf MD5 als Verbesserung gegenüber MD4. Er erzeugt einen 128-Bit-Digest und wurde in den 1990er Jahren weitgehend für Prüfsummen und Passwortspeicherung übernommen. Über ein Jahrzehnt lang war MD5 die Standardwahl für viele Sicherheitsanwendungen.
SHA-1 (1995)
Die National Security Agency (NSA) entwarf SHA-1 (Secure Hash Algorithm 1) als Teil des Digital Signature Standard. Er erzeugt einen 160-Bit-Digest. SHA-1 wurde zum dominierenden Hash-Algorithmus für TLS/SSL-Zertifikate, Code-Signierung und Git-Objektspeicher.
SHA-2-Familie (2001)
Ebenfalls von der NSA entworfen, ist SHA-2 tatsächlich eine Familie von sechs Funktionen: SHA-224, SHA-256, SHA-384, SHA-512, SHA-512/224 und SHA-512/256. SHA-256 und SHA-512 werden am häufigsten verwendet. Sie erzeugen Digests von 256 bzw. 512 Bit und sind heute noch sicher.
SHA-3 / Keccak (2015)
Als die Schwächen von SHA-1 offensichtlich wurden, veranstaltete NIST einen öffentlichen Wettbewerb (2007-2015), um einen völlig neuen Hash-Standard zu finden, der unabhängig vom SHA-2-Design der NSA ist. Der Gewinner war Keccak, entworfen von Guido Bertoni, Joan Daemen, Michaël Peeters und Gilles Van Assche. Im Gegensatz zu SHA-2, das eine Merkle–Damgård-Konstruktion verwendet, nutzt SHA-3 eine Schwamm-Konstruktion und bietet ein grundlegend anderes Sicherheitsprofil.
BLAKE2 (2012)
BLAKE2 ist eine kryptografische Hash-Funktion, die schneller als MD5 ist und gleichzeitig die Sicherheit von SHA-3 bietet. Sie wurde von Jean-Philippe Aumasson, Samuel Neves, Zooko Wilcox-O'Hearn und Christian Winnerlein als Verbesserung gegenüber BLAKE entwickelt, das Finalist beim SHA-3-Wettbewerb war. BLAKE2b ist für 64-Bit-Plattformen optimiert; BLAKE2s für 32-Bit.
3. Wie SHA-256 Funktioniert
SHA-256 verwendet die Merkle–Damgård-Konstruktion: Die Nachricht wird in Blöcke fester Größe aufgeteilt, und eine Kompressionsfunktion wird iterativ angewendet, wobei die Ausgabe eines Blocks als Eingabe für den nächsten dient.
Schritt 1: Padding
Die Eingabenachricht wird aufgefüllt, sodass ihre Gesamtlänge ein Vielfaches von 512 Bit ist. Ein einzelnes 1-Bit wird angehängt, gefolgt von Nullen, gefolgt von der ursprünglichen Nachrichtenlänge als 64-Bit-Big-Endian-Integer.
Schritt 2: Message-Schedule
Jeder 512-Bit-Block wird mithilfe eines Zeitplans, der Bits mischt und rotiert, zu 64 32-Bit-Wörtern erweitert. Die Wörter W[0] bis W[15] kommen direkt aus dem Nachrichtenblock; die Wörter W[16] bis W[63] werden berechnet als:
W[i] = σ1(W[i-2]) + W[i-7] + σ0(W[i-15]) + W[i-16]
Dabei sind σ0 und σ1 spezifische Bit-Rotations- und Verschiebeoperationen.
Schritt 3: Kompression — 64 Runden
SHA-256 pflegt 8 Arbeitsvariablen (a bis h), die mit den Nachkommastellen der Quadratwurzeln der ersten 8 Primzahlen initialisiert werden. Für jede der 64 Runden wird angewendet:
T1 = h + Σ1(e) + Ch(e,f,g) + K[i] + W[i]
T2 = Σ0(a) + Maj(a,b,c)
h = g; g = f; f = e; e = d + T1
d = c; c = b; b = a; a = T1 + T2
Die Rundenkonstanten K[i] sind die Nachkommastellen der Kubikwurzeln der ersten 64 Primzahlen — eine Designentscheidung, die die Kritik des "Nichts im Ärmel" verhindert, indem die Konstanten öffentlich überprüfbar sind und keine versteckten Hintertüren enthalten.
Schritt 4: Ausgabe
Nach der Verarbeitung aller Blöcke werden die 8 Arbeitsvariablen zu den anfänglichen Hash-Werten addiert, um den endgültigen 256-Bit-Digest zu erzeugen. Dieses "Feed-Forward" stellt sicher, dass die Ausgabe jedes Blocks von allen vorherigen Blöcken abhängt.
4. Warum MD5 und SHA-1 Gebrochen Sind
MD5-Kollisionen (2004)
Im Jahr 2004 demonstrierten Xiaoyun Wang und Kollegen praktische Kollisionsangriffe gegen MD5 — sie fanden zwei verschiedene Eingaben, die denselben MD5-Hash erzeugen. Bis 2008 verwendeten Forscher MD5-Kollisionen, um ein betrügerisches SSL-Zertifikat von einer echten CA zu fälschen und demonstrierten damit einen realen Angriff auf die HTTPS-Infrastruktur.
Der Angriff verwendet ausgefeilte differentielle Kryptoanalyse und kann auf moderner Hardware in Sekunden MD5-Kollisionen erzeugen.
SHA-1 SHAttered (2017)
Googles Project-Zero-Team und CWI Amsterdam erzeugten 2017 die erste praktische SHA-1-Kollision, bekannt als SHAttered. Sie generierten zwei verschiedene PDF-Dateien mit identischen SHA-1-Hashes. Der Angriff erforderte ungefähr 9,2 × 10¹⁸ SHA-1-Berechnungen — entsprechend 6.500 Jahren Single-CPU-Zeit — aber nur etwa 110 Jahre GPU-Zeit, was für Nationalstaaten und große Organisationen erreichbar ist.
Praktische Bedeutung
MD5 und SHA-1 sind NICHT sicher für:
- Digitale Signaturen
- Zertifikat-Fingerabdrücke
- Passwortspeicherung
- Alle sicherheitssensiblen Anwendungen
Sie sind noch akzeptabel für:
- Nicht-kryptografische Prüfsummen (Überprüfung der Dateidownload-Integrität über einen vertrauenswürdigen Kanal)
- Hash-Tabellen-Lookups
- Nicht-sicherheitsrelevante Deduplizierung
- Kompatibilität mit Legacy-Systemen (mit angemessenen Vorbehalten)
5. Reale Anwendungsfälle
Passwortspeicherung
Passwörter niemals im Klartext speichern — auch nicht als einfache Hashes. Wenn Ihre Datenbank geleakt wird, kann ein Angreifer einfache Hashes mit Wörterbuchattacken oder Rainbow-Tables innerhalb von Stunden oder Tagen knacken.
Der richtige Ansatz verwendet eine langsame, gesalzene Hash-Funktion, die speziell für Passwörter entwickelt wurde: bcrypt, scrypt oder Argon2.
Dateiintegritätsprüfung
Wenn Sie Software herunterladen, stellt der Entwickler eine SHA-256-Prüfsumme bereit. Nach dem Download berechnen Sie den Hash der Datei und vergleichen ihn. Wenn sie übereinstimmen, wurde die Datei beim Transport nicht beschädigt oder manipuliert.
sha256sum downloaded-file.tar.gz
# Mit der vom Entwickler veröffentlichten Prüfsumme vergleichen
Digitale Signaturen
Hash-Funktionen sind grundlegend für digitale Signaturen. Anstatt ein gesamtes Dokument (das Gigabytes groß sein könnte) zu signieren, hashen Sie es und signieren nur den Hash. Der Empfänger hasht das Dokument unabhängig und verifiziert die Signatur gegen diesen Hash.
Blockchain
Bitcoin verwendet SHA-256 zweimal (SHA-256d) für das Proof-of-Work-Mining und zum Hashen von Transaktionsblöcken. Miner müssen eine Eingabe (Nonce) finden, die, wenn sie gehasht wird, eine Ausgabe mit einer bestimmten Anzahl führender Nullen erzeugt — ein Prozess, der enormen Rechenaufwand erfordert und die Sicherheitsgarantien der Blockchain bietet.
Git-Objektspeicher
Git verwendet SHA-1, um jedes Commit-, Baum- und Blob-Objekt zu hashen. Der Hash dient sowohl als Objektkennung als auch als Integritätsprüfung. Aufgrund der Schwächen von SHA-1 migriert Git aktiv zu SHA-256.
Deduplizierung in Speichersystemen
Backup-Systeme und inhaltsadressierter Speicher (wie IPFS) verwenden Hashes, um doppelten Inhalt zu identifizieren. Wenn zwei Dateien denselben Hash haben, werden sie nur einmal gespeichert.
6. Hashes in der Praxis Berechnen
JavaScript (Node.js)
const crypto = require('crypto');
// SHA-256
const sha256 = crypto.createHash('sha256')
.update('Hello, World!')
.digest('hex');
console.log(sha256);
// 315f5bdb76d078c43b8ac0064e4a0164612b1fce77c869345bfc94c75894edd3
// MD5 (nur für nicht sicherheitsrelevante Zwecke verwenden)
const md5 = crypto.createHash('md5')
.update('Hello, World!')
.digest('hex');
console.log(md5);
// 65a8e27d8879283831b664bd8b7f0ad4
// SHA-512
const sha512 = crypto.createHash('sha512')
.update('Hello, World!')
.digest('hex');
console.log(sha512);
Python
import hashlib
# SHA-256
h = hashlib.sha256(b"Hello, World!").hexdigest()
print(h)
# 315f5bdb76d078c43b8ac0064e4a0164612b1fce77c869345bfc94c75894edd3
# SHA-512
h512 = hashlib.sha512(b"Hello, World!").hexdigest()
print(h512)
# Mehrere Algorithmen
for algo in ['md5', 'sha1', 'sha256', 'sha512']:
h = hashlib.new(algo, b"Hello, World!").hexdigest()
print(f"{algo}: {h}")
Bash / Shell
# SHA-256
echo -n "Hello, World!" | sha256sum
# 315f5bdb76d078c43b8ac0064e4a0164612b1fce77c869345bfc94c75894edd3 -
# MD5
echo -n "Hello, World!" | md5sum
# 65a8e27d8879283831b664bd8b7f0ad4 -
# SHA-1
echo -n "Hello, World!" | sha1sum
# Eine Datei hashen
sha256sum /path/to/file.iso
7. HMAC: Hash-basierter Nachrichtenauthentifizierungscode
Ein einfacher Hash überprüft die Datenintegrität — er sagt Ihnen, ob Daten beschädigt wurden. Er überprüft jedoch nicht die Authentizität — er beweist nicht, wer die Daten erstellt hat. Jeder kann einen Hash berechnen.
HMAC (RFC 2104) löst dieses Problem, indem es einen geheimen Schlüssel mit der Hash-Funktion kombiniert:
HMAC(K, m) = hash((K' ⊕ opad) || hash((K' ⊕ ipad) || m))
Dabei ist K' der auf die Blockgröße aufgefüllte Schlüssel, und opad/ipad sind spezifische Auffüllkonstanten. Diese Konstruktion ist beweisbar sicher, wenn die zugrunde liegende Hash-Funktion sicher ist.
Häufige Verwendungszwecke
API-Authentifizierung: REST-APIs verwenden HMAC-SHA256, um Anfragen zu signieren. Server und Client teilen einen geheimen Schlüssel. Der Client signiert den Anfragekörper mit dem Schlüssel; der Server überprüft die Signatur.
JWT-Signaturen: JSON Web Tokens verwenden HMAC-SHA256 (HS256), um Header und Payload zu signieren und sicherzustellen, dass das Token nicht manipuliert wurde.
Webhook-Verifizierung: GitHub, Stripe und viele andere Dienste signieren Webhook-Payloads mit HMAC-SHA256, sodass Empfänger die Echtheit des Payloads überprüfen können.
HMAC Berechnen
// Node.js
const crypto = require('crypto');
const hmac = crypto.createHmac('sha256', 'mein-geheimer-schluessel')
.update('zu authentifizierende Nachricht')
.digest('hex');
console.log(hmac);
import hmac
import hashlib
key = b'my-secret-key'
message = b'message to authenticate'
sig = hmac.new(key, message, hashlib.sha256).hexdigest()
print(sig)
8. Rainbow-Tables und Salting
Was Sind Rainbow-Tables?
Eine Rainbow-Table ist eine vorberechnete Datenbank, die bekannte Hash-Werte auf ihre ursprünglichen Klartexteingaben zurückführt. Wenn ein Angreifer Ihre Datenbank mit Passwort-Hashes erhält, muss er nicht jeden Hash einzeln knacken — er schlägt ihn einfach in der Tabelle nach.
Für MD5 und SHA-1 sind Rainbow-Tables, die alle ASCII-Passwörter bis zu 8 Zeichen abdecken, seit Jahren kostenlos verfügbar. Websites wie CrackStation pflegen Datenbanken mit Milliarden von Hash-zu-Passwort-Zuordnungen.
Wie Salting Rainbow-Tables Besiegt
Ein Salt ist ein zufälliger Wert, der vor dem Hashen an das Passwort angehängt wird:
hash(Salt + Passwort) = gespeicherter_Hash
Der Salt wird zusammen mit dem Hash gespeichert (er muss nicht geheim sein). Da jeder Benutzer einen einzigartigen zufälligen Salt erhält, kann der Angreifer keine vorberechneten Tabellen verwenden — er bräuchte für jeden möglichen Salt-Wert eine separate Rainbow-Table, was rechnerisch unmöglich ist.
bcrypt: Automatisches Salting und Beabsichtigte Langsamkeit
bcrypt wurde 1999 speziell für das Passwort-Hashing entwickelt. Es generiert und integriert automatisch einen zufälligen Salt und enthält einen Kostenfaktor, der steuert, wie langsam die Hash-Berechnung ist:
const bcrypt = require('bcrypt');
// Ein Passwort hashen (Kostenfaktor 12 — dauert ~250ms auf moderner Hardware)
const hash = await bcrypt.hash('Benutzer-Passwort', 12);
// Verifizieren
const isMatch = await bcrypt.compare('Benutzer-Passwort', hash);
Der gespeicherte Hash sieht so aus: $2b$12$EixZaYVK1fsbw1ZfbX3OXePaWxn96p36WQoeG6Lruj3vjPGga31lW
Das Präfix $2b$12$ kodiert die Algorithmusversion und den Kostenfaktor — bcrypt behandelt alles automatisch.
9. Algorithmen-Vergleichstabelle
| Algorithmus | Ausgabegröße | Geschwindigkeit | Sicherheitsstatus | Beste Verwendung |
|---|---|---|---|---|
| MD5 | 128 Bit | Sehr schnell | ❌ Gebrochen (Kollisionen) | Nur nicht-sicherheitsrelevante Prüfsummen |
| SHA-1 | 160 Bit | Schnell | ❌ Gebrochen (SHAttered) | Nur Legacy-Systeme |
| SHA-256 | 256 Bit | Schnell | ✅ Sicher | Allgemein, TLS, Signaturen |
| SHA-512 | 512 Bit | Schnell auf 64 Bit | ✅ Sicher | Hochsicherheitsanwendungen |
| SHA-3/Keccak | Variabel | Moderat | ✅ Sicher | Alternative zu SHA-2 |
| BLAKE2b | Variabel | Sehr schnell | ✅ Sicher | Leistungskritisches Hashing |
| bcrypt | 184 Bit | Langsam (beabsichtigt) | ✅ Sicher | Passwortspeicherung |
| Argon2id | Variabel | Langsam (beabsichtigt) | ✅ Sicher | Passwortspeicherung (empfohlen) |
10. Best Practices für Passwort-Hashing
Passwörter verdienen eine besondere Behandlung, da sie die Schlüssel zu Benutzerkonten sind. Eine kompromittierte Passwortdatenbank kann verheerend sein. Befolgen Sie diese Regeln ausnahmslos:
Regel 1: Niemals Klartextpasswörter Speichern
Das sollte offensichtlich sein, aber es passiert noch immer. Im Jahr 2019 wurde festgestellt, dass Facebook intern Hunderte von Millionen Passwörter im Klartext gespeichert hatte.
Regel 2: Niemals Schnelle Hashes für Passwörter Verwenden
MD5, SHA-1, SHA-256 und SHA-512 sind alle zu schnell für das Passwort-Hashing. Eine moderne GPU kann Milliarden von SHA-256-Hashes pro Sekunde berechnen und ermöglicht Brute-Force-Angriffe innerhalb von Stunden.
Regel 3: Zweckgebaute Passwort-Hashing-Algorithmen Verwenden
bcrypt (empfohlenes Minimum): Verwenden Sie einen Kostenfaktor von 12 oder höher. Weit verbreitet, kampferprobt.
scrypt: Speicherintensiv, dadurch resistent gegen GPU- und ASIC-Angriffe. Konfigurierbare Speicher- und CPU-Kosten.
Argon2id (heute empfohlen): Gewinner des Password Hashing Competition 2015. Argon2id ist die empfohlene Variante, da sie Widerstand gegen Seitenkanal-Angriffe und Zeitgedächtnis-Kompromiss-Angriffe bietet. Mindestens konfigurieren mit:
- Speicher: 64 MB
- Iterationen: 3
- Parallelismus: 4
Regel 4: Einen Einzigartigen Salt pro Passwort Verwenden
Auch bei bcrypt/scrypt/Argon2 (die automatisches Salting beinhalten), verstehen Sie warum es wichtig ist: Identische Passwörter müssen verschiedene Hashes erzeugen, damit das Kompromittieren eines Passworts nicht andere offenbart.
Regel 5: Kostenfaktoren im Laufe der Zeit Anpassen
Wenn Hardware schneller wird, erhöhen Sie die Kostenfaktoren. Streben Sie ~250-500ms für bcrypt an. Passwörter beim nächsten Login neu hashen.
Regel 6: Pepper in Betracht Ziehen
Ein Pepper ist ein serverseitiges Geheimnis (im Gegensatz zu einem Salt wird es nicht in der Datenbank gespeichert). Es wird vor dem Hashen zum Passwort hinzugefügt: hash(Pepper + Salt + Passwort). Selbst wenn ein Angreifer Ihre Datenbank stiehlt, kann er Passwörter ohne den Pepper nicht knacken.
Fazit
Kryptografische Hash-Funktionen sind grundlegend für Sicherheit, Integrität und Vertrauen im gesamten Internet. Das Verständnis dieser Funktionen — von ihren mathematischen Eigenschaften bis zu ihren praktischen Schwachstellen — ermöglicht es Ihnen, Systeme zu bauen, die wirklich sicher sind.
Die wichtigsten Erkenntnisse:
- SHA-256 und SHA-512 sind Ihre Allzweck-Hash-Funktionen
- MD5 und SHA-1 sind für kryptografische Zwecke gebrochen
- Für Passwörter immer bcrypt, scrypt oder Argon2 verwenden
- HMAC verwenden, wenn Sie Authentifizierung und nicht nur Integrität benötigen
- Salting besiegt Rainbow-Tables; bcrypt und Argon2 tun es automatisch
Verwenden Sie den Tool3M Hash-Generator, um SHA-256-, SHA-512-, MD5- und andere Hashes direkt in Ihrem Browser schnell zu berechnen — keine Installation erforderlich.