Das Symptom
In einer Konfigurationsdatei, einem Cookie oder einem Datenbankfeld steht etwas,
das eindeutig nach Geheimnis aussieht:
Z2VoZWltMTIz
Der Kollege sagt beruhigt, das sei ja verschlüsselt. Oder umgekehrt: Ein Nutzer
hat sein Passwort vergessen, und jemand fragt allen Ernstes, ob man den Hash in
der Datenbank nicht einfach entschlüsseln könne.
Die „Layer 8“-Wahrheit
Beide Sätze beschreiben dasselbe Missverständnis aus entgegengesetzter Richtung:
Kodieren, Hashen und Verschlüsseln werden für dasselbe gehalten, weil das Ergebnis
in allen drei Fällen gleich unleserlich aussieht. Unleserlich ist aber keine
Eigenschaft, sondern ein Eindruck. Base64 ist eine Verpackung: Der Standard, der
es festlegt, sagt selbst, dass diese Kodierung Informationen wie Passwörter nur
optisch versteckt und keinerlei rechnerische Vertraulichkeit bietet. Sie wurde
erfunden, damit beliebige Bytes durch Kanäle passen, die nur US-ASCII vertragen –
E-Mail-Anhänge, HTTP-Kopfzeilen, eingebettete Bilder. Ein Schlüssel kommt in dem
Verfahren nirgends vor, und was ohne Schlüssel auskommt, kann jeder rückgängig
machen. Eine Zeile in der Kommandozeile genügt.
Die andere Hälfte des Missverständnisses ist genauso hartnäckig. Ein Hash ist
keine Verschlüsselung mit verlorenem Schlüssel, sondern eine Einbahnstraße: Er
bildet jede Eingabe auf einen Wert fester Länge ab, und es gibt nichts, was man
zurückrechnen könnte. Deshalb kann kein seriöser Dienst dein altes Passwort
zurückschicken, sondern nur ein neues setzen lassen – wenn doch eines im Postfach
landet, ist das kein Service, sondern ein Befund. Was Angreifer tun, ist raten und
vergleichen, und genau dagegen zielen die Vorgaben: salzen, damit fertige Tabellen
nichts nützen, und absichtlich langsam ableiten, damit jeder Ratevorgang etwas
kostet. Der Computer hat in allen drei Fällen recht. Nur das Wort, das man ihm
untergeschoben hat, war falsch.
Die echte, verifizierte Lösung
1000 % faktenbasiert. Jeder Befehl ist real, jeder Pfad existiert. Schritt für Schritt:
1.Base64 erkennen
Base64 besteht laut RFC 4648 aus einem 65 Zeichen großen Ausschnitt von US-ASCII: den Buchstaben A bis Z und a bis z, den Ziffern 0 bis 9, dazu Plus und Schrägstrich – und dem Gleichheitszeichen als 65. Zeichen mit Sonderaufgabe. Je 24 Bit Eingabe werden zu vier Zeichen Ausgabe. Wer also eine Zeichenkette ohne Umlaute, ohne Sonderzeichen und mit einem oder zwei Gleichheitszeichen am Ende sieht, hat mit hoher Wahrscheinlichkeit keine Chiffre vor sich, sondern eine Verpackung.
2.Den Beweis antreten: in einer Zeile zurückrechnen
Statt zu diskutieren, rechnet man es vor. Es braucht keinen Schlüssel, kein Passwort und keine Software, die nicht ohnehin auf jedem System liegt. Wenn das in einer Sekunde geht, war es nie geschützt.
printf '%s' 'geheim123' | base64
# Z2VoZWltMTIz
echo 'Z2VoZWltMTIz' | base64 -d
# geheim123
3.Aufhören, Base64 als Schutzmaßnahme zu verkaufen
Ein base64-kodiertes Passwort in einer Konfigurationsdatei, in einem Cookie oder in einem Datenbankfeld ist ein Klartextpasswort mit Sonnenbrille. Es hilft nur gegen versehentliches Mitlesen über die Schulter – und laut RFC 4648 nicht einmal zuverlässig dagegen, weil Leute genau deshalb ihre Zugangsdaten in Fehlerberichte kopieren. Wer Vertraulichkeit braucht, braucht Verschlüsselung mit einem Schlüssel, der nicht danebenliegt.
4.Passwörter salzen und mit einer langsamen Einwegfunktion hashen
Für gespeicherte Passwörter gilt die Vorgabe der NIST-Richtlinie SP 800-63B: gesalzen und mit einer geeigneten Einweg-Schlüsselableitungsfunktion gehasht. Die Zahl der Durchläufe soll so hoch sein, wie der Server es verkraftet; eine speicherharte Funktion ist zu bevorzugen, weil sie einen Angriff teurer macht. Ein nacktes SHA-256 ohne Salz und ohne Iterationen erfüllt das nicht.
python3 -c "import hashlib, os; salt = os.urandom(16); dk = hashlib.pbkdf2_hmac('sha256', b'geheim123', salt, 600000); print(salt.hex(), dk.hex())"
5.Verstehen, warum der Hash nicht zurückgeht
Ein Hash hat immer dieselbe Länge, egal wie lang die Eingabe war – bei SHA-256 sind es 64 Hexadezimalzeichen. Schon eine um eins geänderte Ziffer erzeugt ein völlig anderes Ergebnis. Aus dieser festen Länge lässt sich die Eingabe nicht rekonstruieren; es gibt schlicht nichts zurückzurechnen. Wer im Werkzeug einen Knopf `Hash entschlüsseln` sucht, sucht etwas, das es nicht gibt.
python3 -c "import hashlib; a = hashlib.sha256(b'geheim123').hexdigest(); b = hashlib.sha256(b'geheim124').hexdigest(); print(a, len(a)); print(b)"
6.Die drei Begriffe auseinanderhalten und sie auch so nennen
Kodieren macht Daten transportierbar und ist ohne Geheimnis umkehrbar – das ist Base64. Hashen macht Daten wiedererkennbar und ist gar nicht umkehrbar – das ist SHA-256 oder eine Schlüsselableitung. Verschlüsseln macht Daten vertraulich und ist genau mit dem passenden Schlüssel umkehrbar. Die meisten Sicherheitsdiskussionen im Büro lösen sich auf, sobald jemand diese drei Wörter nicht mehr durcheinanderwirft.
7.Geheimnisse dorthin legen, wo sie hingehören
Wo etwas wirklich geheim bleiben muss, hilft kein Kodierungstrick, sondern nur, dass das Geheimnis gar nicht erst an der falschen Stelle liegt: nicht im Quelltext, nicht im Versionsverwaltungssystem, nicht in einer Konfigurationsdatei, die mit ausgeliefert wird. Und falls es dort doch schon liegt, gilt es als offengelegt und muss ersetzt werden – Löschen allein reicht nicht, denn die Historie vergisst nichts.