Aktualisierung:
Ich habe diesen Link zu meiner anderen Antwort hinzugefügt wie man JWT-Authentifizierung für ASP.NET Web API verwendet hier für alle, die sich für JWT interessieren.
Wir haben es geschafft, die HMAC-Authentifizierung auf eine sichere Web-API anzuwenden, und es hat gut funktioniert. Bei der HMAC-Authentifizierung wird für jeden Verbraucher ein geheimer Schlüssel verwendet, der sowohl dem Verbraucher als auch dem Server bekannt ist, um eine Nachricht mit HMAC256 zu verschlüsseln. In den meisten Fällen wird das gehashte Passwort des Verbrauchers als geheimer Schlüssel verwendet.
Die Nachricht wird in der Regel aus Daten in der HTTP-Anfrage oder sogar aus benutzerdefinierten Daten, die dem HTTP-Header hinzugefügt werden, erstellt:
- Zeitstempel: Zeitpunkt der Übermittlung der Anfrage (UTC oder GMT)
- HTTP-Verb: GET, POST, PUT, DELETE.
- Postdaten und Abfragezeichenfolge,
- URL
Unter der Haube würde die HMAC-Authentifizierung so aussehen:
Der Verbraucher sendet eine HTTP-Anfrage an den Webserver, nachdem er die Signatur (Ausgabe des hmac-Hash), die Vorlage der HTTP-Anfrage, erstellt hat:
User-Agent: {agent}
Host: {host}
Timestamp: {timestamp}
Authentication: {username}:{signature}
Beispiel für eine GET-Anfrage:
GET /webapi.hmac/api/values
User-Agent: Fiddler
Host: localhost
Timestamp: Thursday, August 02, 2012 3:30:32 PM
Authentication: cuongle:LohrhqqoDy6PhLrHAXi7dUVACyJZilQtlDzNbLqzXlw=
Die zu hashende Nachricht, um die Signatur zu erhalten:
GET\n
Thursday, August 02, 2012 3:30:32 PM\n
/webapi.hmac/api/values\n
Beispiel für eine POST-Anfrage mit Query-String (die nachstehende Signatur ist nicht korrekt, sondern nur ein Beispiel)
POST /webapi.hmac/api/values?key2=value2
User-Agent: Fiddler
Host: localhost
Content-Type: application/x-www-form-urlencoded
Timestamp: Thursday, August 02, 2012 3:30:32 PM
Authentication: cuongle:LohrhqqoDy6PhLrHAXi7dUVACyJZilQtlDzNbLqzXlw=
key1=value1&key3=value3
Die zu hashende Nachricht, um die Signatur zu erhalten
GET\n
Thursday, August 02, 2012 3:30:32 PM\n
/webapi.hmac/api/values\n
key1=value1&key2=value2&key3=value3
Bitte beachten Sie, dass die Formulardaten und der Abfrage-String in der richtigen Reihenfolge sein sollten, damit der Code auf dem Server den Abfrage-String und die Formulardaten erhält, um die richtige Nachricht zu erstellen.
Wenn eine HTTP-Anfrage auf dem Server eingeht, wird ein Authentifizierungsfilter implementiert, um die Anfrage zu analysieren und Informationen zu erhalten: HTTP-Verb, Zeitstempel, URL, Formulardaten und Abfragezeichenfolge. Auf dieser Grundlage wird dann auf dem Server eine Signatur (unter Verwendung eines Hmac-Hashes) mit dem geheimen Schlüssel (gehashtes Passwort) erstellt.
Der geheime Schlüssel wird zusammen mit dem Benutzernamen bei der Anfrage aus der Datenbank geholt.
Dann vergleicht der Servercode die Signatur der Anfrage mit der erstellten Signatur; ist sie gleich, wird die Authentifizierung bestanden, andernfalls ist sie fehlgeschlagen.
Der Code zur Erstellung der Signatur:
private static string ComputeHash(string hashedPassword, string message)
{
var key = Encoding.UTF8.GetBytes(hashedPassword.ToUpper());
string hashString;
using (var hmac = new HMACSHA256(key))
{
var hash = hmac.ComputeHash(Encoding.UTF8.GetBytes(message));
hashString = Convert.ToBase64String(hash);
}
return hashString;
}
Wie kann man also einen Replay-Angriff verhindern?
Fügen Sie eine Einschränkung für den Zeitstempel hinzu, etwa so:
servertime - X minutes|seconds <= timestamp <= servertime + X minutes|seconds
(servertime: Zeitpunkt des Eingangs der Anfrage beim Server)
Und, Cache die Signatur der Anfrage im Speicher (verwenden MemoryCache, sollte in der Grenze der Zeit zu halten). Wenn die nächste Anforderung mit der gleichen Signatur wie die vorherige Anforderung kommt, wird sie abgelehnt.
Der Demo-Code ist hier zu finden: https://github.com/cuongle/Hmac.WebApi