Hashwert-Sicherheit

Wenn Sie Microsoft 365 nutzen und ADSync mit Password Hash Sync (PHS) einrichten, dann setzen das viele Administratoren mit "Wir kopieren das Kennwort in die Cloud" gleich. Das ist aber mitnichten so und zur Erläuterung beschreibe ich die verschiedenen Verfahren zur Abmeldung und Absicherung mit Kennworten.

etc/passwd

Die Computer und Betriebssysteme in meiner Schulzeit kannte noch gar keine Benutzer und Anmeldung, sondern wir haben den Computer (C64, ZU81, Apple ][ o.ä.) eingeschaltet und er war einfach da. Erst wenn wir auf einen "Großrechner" (DEC VAX, PDP-11 o.ä.) zugreifen wollten, war eine Anmeldung mit Benutzername und Kennwort erforderlich. Damit stellen sich gleich zwei Fragen:

  • Wie sicher wurde das Kennwort über die "Leitung" übertragen
    Damals gab es noch kein HTTPS oder SSH sondern TELNET oder sogar serielle Leitungen (RS-232, V.24). Jeder Tastendruck wurde 1:1 als Byte übertragen und war entsprechend unsicher. Heute sollte zum einen die Übertragung selbst per TLS verschlüsselt werden aber auch das Kennwort muss schon lange nicht mehr in Klartext übertragen werden.
  • Wie konnte der Host das korrekte Kennwort prüfen
    Auf der Empfängerseite kommt nun irgendetwas an und der Dienst muss die übermittelten Zugangsdaten prüfen. In den Anfangszeiten war das direkt das Kennwort und der Empfänger hat das Kennwort verglichen

In der UNIX-Welt kennen sich sicher die Datei "/etc/passwd", in der Benutzer mit ihren (verschlüsselten) Kennworten gespeichert wurden und auch heute ist diese Datei auf den meisten Systemen noch vorhanden. Hier am Beispiel eines RasPi im Sep 2023)

Wobei die "Verschlüsselung" ein "Hash" ist. Aber es war früher auch gar nicht mal ungewöhnlich, dass Zugangsdaten im Klartext in einer Datenbank oder Datei hinterlegt wurden. Entsprechend interessant war es für einen Angreifer, diese Dateien zu kopieren und so gewonnene Zugänge zu nutzen. Wir sollten also nie Kennworte im Klartext speichern. Aber selbst "verschlüsselte" Kennworte müsste eine Software zum Vergleich ja erst wieder entschlüsseln. Das dafür erforderliche Schlüsselmateriel liegt dann auch irgendwo auf dem Computer, schlimmstenfalls als Konstante im Code, und wäre für einen Angreifer schnell zu finden. Hier kommt dann die Hash-Funktion in den Blickpunkt.

Die Hash-Funktion

Hashwerte werden natürlich bei Kennworten genutzt aber eben nicht nur. Eine Hash-Funktion bekommt eine binäre Information und macht daraus eine verkürzte Zahl mit einer vorgegebenen Bit-Länge. Sie können als ein 4-stelliges Kennwort, eine Textzeile aus 80 Zeichen, eine EXE-Datei oder eine 700MB große ISO-Datei in eine Hashfunktion einkippen und bekommen am ende z.B. eine 128bit-Zahl heraus. Das Ergebnis einer Hash-Funktion hat weitere Funktionen:

  • Wenn Sie die gleiche Informationen vorne eingeben, kommt hinten auch immer der gleiche Hash als Ergebnis heraus.
  • Zudem sorgt die Hash-Funktion dafür, dass selbst kleine Veränderungen ein anderes Ergebnis liefern. Ein Buchstabendreher oder Zahlendreher in der Quelle ergibt nicht den gleichen Hash
  • Es ist sehr schwer, eine Information in der Quelle zu ändern und durch eine zweite Änderung wieder den gleichen Hashwert zu erhalten.
  • Durch die Reduzierung der Datenmenge ist es auch nicht mehr möglich von eine Hashwert einfach auf die Quellinformation zu schließen
  • Es ist aber denkbar, dass zwei gänzlich unterschiedliche Quellinformationen den gleichen Hashwerte haben

Damit können Sie eine Hash-Funktion für mehrere Anforderungen einsetzen, z.B.:

  • Vergleich
    Wenn Sie zwei Dateien vergleichen, dann können Sie natürlich beide Dateien 1:1 miteinander vergleichen, was entsprechend lange dauert und bei vielen Vergleichen immer wieder passiert. Wenn Sie zu jeder Datei einen Hash-Wert anlegen, dann können Sie einfach diese Hashwerte vergleichen und damit gleiche und unterschiedliche Dateien erkennen.
  • Signierung
    Wenn Sie den Hashwert einer Information auch noch digital signieren (Zertifikate, SMIME, Code-Signing etc.), dann können Sie Veränderungen an der Datei an sich erkennen und z.B. die Ausführung unterbinden
  • Kennwort
    Natürlich können Sie auch durch den Benutzer eingegebene Kennwort als Hashwert mit einem gespeicherten Hashwert vergleichen. Da die Hashwerte aller Benutzer gleich lang sind, hat ein Angreifer keinen Anhaltspunkt zur Länge der Kennworte.

Es gibt nun nicht genau die eine Hash-Funktion. Wie so oft gibt es unterschiedliche Algorithmen mit eigenen Vor- und Nachteilen.

  • CRC - Cyclic Redundancy Check
    Diese Funktion kennen Sie vielleicht als "Prüfsumme" bei RAID-Controllern, seriellen Übertragungen etc. um einzelne oder mehrere Bitfehler bei einer Übertragung zu erkennen. Für Kennworte etc. ist dies nicht brauchbar
  • SHA - Secure Hash Algorithm
    Dies ist eine Obergruppe, die mit SHA-1, einem 160bit Hashwert gestartet hat und mittlerweile als unsicher gilt. Daher gibt es SHA-2, welches die Unterklassen SHA-224, SHA-256, SHA-384, und SHA-512 beinhaltet. Diese sind noch sicher und werden z.B. bei TLS verwendet. Aber SHA-3 ist auch schon definiert und soll schneller und sicherer sein
  • MD5 - Message Digest 5
    Dieser Algorithmus liefert ein 128bit-Zahl als Ergebnis und ist auch nicht mehr sicher

Der Vorteil einer Zahl mit fester Bitlänge ist, dass sie sehr einfach gespeichert, sortiert und gesucht werden kann. Sie eigenen sich z.B. wunderbar als Index für Datenbanktabellen. Auch in PowerShell gibt es "Hashtabellen", die ich auch gerne nutzen. Wenn ich viele Datensätze habe und weiß, nach welchem Feld, z.B. Mailadresse, ich später suche, dann merke ich mir nicht die Mailadresse sondern den Hashwert als Index zu den Daten. Später kann ich dann einfach den Hashwert als Index nutzen.

Brute Force und Rainbow-Table und Salt

Für die Verwendung als Kennwortspeicher sind Hashwerte gut geeignet, denn es gibt keine einfache "Rückwärts"-Funktion und wer z.B. eine Kennwortdatenbank mit Hashwerten "gefunden" hat, muss schon ganz viele Kennworte ausprobieren, bis er eines mit dem gleichen Hashwert findet. Der Angreifer hat dann aber nur ein Kennwort, welches den gleichen Hashwert liefert. Es muss nicht das gleiche Kennwort des Anwenders sein. Nehmen wir nun mal SHA265 als Beispiel, dann sind 128Bits = 3,4..e+38 mögliche Werte. Es braucht schon sehr viele Buchstaben/Zahlen-Kombinationen aber es ist denkbar, wenn die verwendeten Kennworte nicht sonderlich stark sind.

Ein Angreifer muss aber nun nicht jeden Hashwert neu durchprobieren, wenn er mit Rainbow-Tables arbeitet. Vereinfacht gesagt errechnet ein Angreifer einmal eine Liste von Kennworten mit deren Hashwerten. Wenn ich z.B. alle Buchstaben von a-zA-Z0-9 mit 10 Stellen durchdeklinieren würde, dann ergibt das (26+26+10)^10  oder 839.299.365.868.340.224 Zeilen mit 10 Zeichen (=10 Byte). Das ist immer noch zu viel aber auch Hashfunktionen sind nicht "perfekt" und man kann über geeignete "Reduktionsformeln" mit vorberechneten Zwischenergebnissen die Zeit zum Ermitteln eines Kennworts mit dem gleichen Hashwert deutlich verkürzen.

Wenn ich als Entwickler aber nun an jedes Kennwort beim Anlegen und Vergleichen noch eine zufällige Zeichenkette (den Salt) addiere und mit dem Hashwert abspeichere, dann werden Rainbow-Tabellen wertlos. Eine weitere Schutzfunktion besteht darin, den Hashwert selbst einfach noch ein- oder mehrmals durch die Hash-Funktion zu zu jagen.

Wem das noch nicht reicht, kann noch eine geheime Information bei allen Werten addieren, die nicht auf dem System selbst liegt. Das System würde dann beim Hochfahren z.B.: den Wert erfragen und erst dann kann die Kennwortdatenbank genutzt werden. Bei Windows kann dies mit "SYSKEY" erreicht werden. Analog zu "Salt" wird dieses Verfahren dann "Pepper" genannt.

Hash auf dem Übertragungsweg

Eine Software, die von Anwendern die Eingabe eines Kennworts erwartet, sollte diese Information daher nie im Klartext und auch nicht mehr als einfachen Hash-Wert speichern sondern mehrfach hashen und/oder einen Salt/Pepper verwenden. Ein gehackter Server mit einem so geschützten Datenbestand ist für einen Angreifer nicht wirklich brauchbar. Allerdings kann ein Angreifer auf dem System natürlich auch die Anmeldungen der Anwender über das Netzwerk angreifen.

Daher ist es nicht ausreichend, die Verbindung z.B. per TLS zu verschlüsseln (HTTPS, VPN, IPSEC), sondern das Anmeldeverfahren selbst muss auch sicher sein. Es macht heute überhaupt keinen Sinn mehr, als Anwender das Kennwort in eine Dialogbox eingeben und an den Server über TLS verschlüsselt zu senden, wenn der Webserver, das PHP-Skript o.ä. das Kennwort dann im Klartext vorliegen hat. Die so genannt "Basic Authentication" ist leider bei vielen Systemen, speziell bei Webformularen immer noch häufig im Einsatz.

Besser sind Anmeldeverfahren wie NTLM, Kerberos oder Zertifikate, bei denen auch das Kennwort nicht mehr übertragen wird. Im einfachsten Fall könnte der Client das eingegebene Kennwort mittels Hash-Funktion umwandeln und an den Server senden, der dann nur noch den Hash vergleicht. Das ist aber trotzdem nicht sicher, denn ein Angreifer könnte ja auch den Hash senden. Daher basieren moderne Anmeldeverfahren darauf, dass der Server dem Client z.B. eine zufällige Information sendet, die der Client mit seinem Kennwort, bzw. dem Hash verschlüsselt. Der Server führt die gleiche Berechnung durch und wenn die Ergebnisse übereinstimmen ist der Anwender authentifiziert.

Wenn das verwendete Verfahren "wasserdicht" ist, kann die Anmeldung an sich sogar über unverschlüsselte Verbindungen übertragen werden. Allerdings werden dann die nachkommenden Daten dann auch nicht verschlüsselt, weswegen sie immer auf TLS setzen sollten.

Was bedeutet das für Microsoft 365 PHS?

Sie haben nun zumindest die Grundlagen zur sicheren Speicherung von Kennworten als "salted Hash" und die sichere Authentifizierung über die Leitung. Ein Windows Domain Controller speichert schon lange keine Klartextkennworte sondern nur Hashwerte. Die "lokale Datenbank" ist als SAM bekannt und liegt bei den meisten Systemen auf "%SystemRoot%/system32/config/SAM". Anfangs wurden die Kennworte als LM-Hash und später als NTLM-Hash gespeichert. Die SAM kann zusätzlich mit SYSKEY gesichert werden, was aber seit dem Einsatz von Bitlocker und Safebook kaum mehr gemacht wird. Seit Windows 10 ist SYSKEY sogar nicht enthalten, da Angreifer damit natürlich auch sehr einfach einen DC "verriegeln" konnten und das Startkennwort erst gegen Lösegeld herausgegeben haben.

Der LM-Hash ist heute "unsicher" und ein DC sollte diesen nicht mehr speichern. Zum einen ist das Verfahren schwach und dann hat Windows das Kennwort in zwei Blöcke a 7 Zeichen aufgeteilt und getrennt verhash und gespeichert. Anhand des Hashwerts war direkt erkennbar, ob das Kennwort weniger als 8 Stellen lang war.

Im Active Directory werden die Kennwort auch als NT Hash gespeichert und damit ist auch klar, dass PHS keine "Kennworte" in die Cloud replizieren sondern maximal die Hashwerte auslesen kann. Um die Sicherheit weiter zu erhöhen, werden die Hashwerte noch ein zweites mal mit einer Hash-Funktion verrechnet, so dass die Cloud nur den Hashwert von einem Hashwert hat. Damit ist der Einsatz von Rainbow-Tabellen nicht nutzbar. Microsoft hat natürlich seine Produkte in der Cloud so angepasst, dass ein Kennwort eines Benutzers nun auch zweimal durch die Hash-Funktion laufen muss, ehe es mit dem gespeicherte Wert verglichen werden kann.

Etwas anders sieht es aus, wenn Sie die "Password Write-Back"-Funktion nutzen, bei ein Anwender in der Cloud sein Kennwort ändern kann und ADSync dieses dann auf das lokale AD zurückschreibt. Da bekommt die Cloud natürlich ihr "Kennwort" von ihnen und speichert dann die Hashwerte ins AzureAD und über ADSync ins lokale AD.

Einschätzung

Einfache und kurze Hashwerte bieten keinen gute Schutz. Für den Entwickler ist es aber kein Problem einfach größere Hashwert-Verfahren zu nutzen und einen Salt zu verwenden, damit Rainbow-Tabellen und Offline-Zugriffe wertlos sind. Selbst wenn ein Angreifer eine Liste von Benutzernamen und dazugehöriger Hashwerte bekommt, kann er damit nur dann etwas anfangen, wenn er das Hashverfahren und den Salt und ggfls. Pepper kennt. Vorgefertigte Listen helfen nicht weiter.

Wir können nur hoffen, dass dies alles auch den Entwicklern von Produkten und Lösungen bekannt ist, die Kennwort von Anwendern entgegennehmen und als Hash irgendwo speichern.

Weitere Links