Ich arbeite an einer API für einen REST-Service, den ich sowohl produzieren als auch konsumieren werde. Ich habe in den letzten Tagen versucht, herauszufinden, wie man mit Authentifizierung gut umgeht, und denke, ich habe mir endlich etwas ausgedacht.
Ich komme auf die Grundlage der folgenden Fakten zum Anwendungsstapel:
- Client & Server befinden sich in .NET4 (Client-Teil im Client-Profil)
- Server macht mit WCF REST verfügbar
- Ich möchte den Benutzernamen und das Passwort in der App wirklich nicht im Speicher behalten
Ab 3 wollte ich eine Form der Token-Authentifizierung verwenden, damit der Client nach Überprüfung der Anmeldeinformationen durch den Server ein Token zurückerhält, das im gesamten Rest der App verwendet werden kann (dies ermöglicht mir andere Aufgaben, z Zeitüberschreitung bei Benutzern, nahtlose Verschiebung von Benutzern zwischen der Web- und Desktop-Version usw.). Nachdem ich herausgefunden habe, wie die Anrufe wiederholt und manipulationssicher gemacht werden können, habe ich Folgendes gefunden:
- Bevor der Client versucht, sich zu authentifizieren, generiert er mithilfe der
ECDiffieHellmanCng
Klasse ein Diffie-Hellman-Schlüsselpaar . - Es sendet den öffentlichen Teil des Schlüsselpaars zusammen mit dem Benutzernamen und dem Kennwort über das Kabel (natürlich über HTTPS).
- Der Server authentifiziert die Kombination aus Benutzername und Kennwort. Wenn dies erfolgreich ist, führt er Folgendes aus:
- Erstellt ein eindeutiges Sitzungstoken
- Generiert ein eigenes DH-Schlüsselpaar und berechnet das gemeinsame Geheimnis aus dem vom Client bereitgestellten öffentlichen Schlüssel
- Notiert das Sitzungstoken, das gemeinsame Geheimnis, den Benutzer und die Zeit der "letzten Aktion" (die für ein fortlaufendes Ablauffenster verwendet wird) in seiner Datenbank
- Gibt das Sitzungstoken, seinen öffentlichen DH-Schlüssel und eine Authentifizierungserfolgsnachricht zurück
- Der Client entnimmt der Antwort den DH-Schlüssel, berechnet das gemeinsame Geheimnis und speichert sowohl das Token als auch das Geheimnis im Speicher.
Ab diesem Zeitpunkt funktioniert die Kombination aus Sitzungstoken und Geheimnis wie die meisten anderen REST-APIs. Die Anforderung wird mit einem Fingerabdruck versehen und mit einem Zeitstempel versehen. Anschließend wird eine Art HMAC generiert. Wenn ein Client eine Aktion für den Server ausführt, überprüft er das Token / Secret-Paar und lässt die Aktion zu, wenn sie gültig und nicht abgelaufen ist, und aktualisiert den letzten Aktionsdatensatz in der Sitzung.
Ich sehe keine offensichtlichen Mängel und bin wahrscheinlich dafür überentwickelt, aber ich muss irgendwann lernen, wie man das macht. Der HMAC verhindert Wiederholungsangriffe, die DH-Aushandlung hilft, MITM-Angriffe zu verhindern (ich kann mir keinen praktikablen Angriff zwischen HMAC / DH vorstellen).
Irgendwelche Löcher, in die jemand stecken kann?