Zwei-Salt-Verfahren

04.11.2019 Jonas L. Technik

Passwörter “verschlüsselt” man, indem man einen Salt hinzufügt und danach hasht. Wenn man das mit zwei verschiedenen Salts am selben Passwort macht und beide Salts und Hashwerte speichert, kann man damit etwas schönes machen.

Szenario:

  • eine Client-Server-Anwendung
  • begrenzte Nutzercluster, die zu bestimmten Geräteclustern gehören
  • jeder Nutzer eines Nutzerclusters soll an jedem Gerät eines Geräteclusters “etwas” tun können
  • “etwas” soll authentifiziert ablaufen
  • das selbe “etwas” soll auch möglich sein, wenn es keine Verbindung zum Server gibt

Wie man auf einem Client etwas lokal macht und später an den Server sendet, wenn es keine Verbindung gibt, werde ich hier nicht erläutern. Es wird das Modell zu Grunde gelegt, das ich bereits beschrieben habe:

Alternative zur Firebase Realtime Database

13.08.2019 Jonas L.

Zum einfachen Bauen von vernetzten Anwendungen gibt es von Google die Firebase Realtime Database. Aber alles hat seinen Preis und hier macht man sich von Google abhängig und muss die Daten bei Google lagern.

Damit der Client lokal die Passwörter überprüfen kann, muss er den Salt und den Hash kennen. Da er auch die Benutzerliste braucht können diese Daten mit der Benutzerliste zum Client kommen.

Bleibt ein Problem: Never trust the client - Wie soll der Server überprüfen, ob wirklich der entsprechende Benutzer am Client war? Da werden der zweite Hash und der zweite Salt relevant. Der Client sollte nur den zweiten Salt vom Server bekommen, aber nicht den zweiten Hash.

Wenn der Nutzer sich nun am entsprechenden Client anmeldet, dann kennt der Client das Passwort. Mit dem ersten Salt und dem ersten Hash kann er dann überprüfen, ob das Passwort richtig ist. Mit dem zweiten Salt kann er den zweiten Hash berechnen, den er nicht vom Server bekommen hat. Somit kann man mit dem Besitz des zweiten Hashs als Client gegenüber dem Server nachweisen, dass man das Passwort kennt/ kannte, ohne jemals das Passwort zu nennen. Nun muss man irgendwie diesen zweiten Hash verwenden.

Wenn man eine Verbindung hätte, würde man die Aktionen des Nutzers und den zweiten Hash senden. Aber es soll ja auch funktionieren, wenn man keine Verbindung hat. Dann könnte man den zweiten Hash speichern, bis man die Aktionen gesendet hat. Aber das wäre nicht gut, weil man den dann nicht so leicht sicher löschen könnte.

Man kann allerdings jede Aktion des Nutzers mit einem Integritäts-Wert versehen. Den berechnet man aus der Aktion an sich, der Geräte-ID, der Sequenz-Nummer (fortlaufende Nummer für Aktionen von einem bestimmten Client) und dem zweiten Hash. Für die “Berechnung” ist eine kryptographische Hashfunktion empfehlenswert. Da der zweite Hash kein menschliches Passwort sondern eine zufällige Zeichenfolge ist, muss kein Passworthashingverfahren genutzt werden.

Jetzt hat jede Aktion einen Integritäts-Wert, aber solange man diesen nicht prüft erhöht er nicht die Sicherheit. Da man alle Parameter, die in die Berechnung einfließen, auch auf dem Server kennt, kann man diesen dort auch berechnen. Nur wenn der Wert der gegebenen Aktion mit dem berechneten Wert übereinstimmt, dann führt man diese aus.

Somit kann man mit relativ einfachen Mitteln Aktionen dezentral per Passwort genehmigen, ohne das irgendwo das Passwort im Klartext gespeichert wird und ohne das man den Passwortschutz als Placebo umsetzt.

Dieses Verfahren wird in einer meiner Anwendungen produktiv verwendet.

Man könnte auch asymmetrische Kryptographie verwenden und den mit dem Passwort des Benutzers verschlüsselten privaten Schlüssel an alle Geräte senden. Das wäre komplizierter und würde client- und serverseitig mehr Rechenleistung beanspruchen, aber es wäre nicht sicherer.