Aktualizacja:
Dodałem ten link do mojej innej odpowiedzi, jak używać uwierzytelniania JWT dla API sieci Web ASP.NET tutaj dla wszystkich zainteresowanych JWT.
Udało nam się zastosować uwierzytelnianie HMAC do bezpiecznego interfejsu API sieci Web i działało dobrze. Uwierzytelnianie HMAC używa tajnego klucza dla każdego konsumenta, który zarówno klient, jak i serwer wiedzą, że hmac hash wiadomość, należy użyć HMAC256. W większości przypadków zaszyfrowane hasło konsumenta jest używane jako tajny klucz.
Wiadomość zwykle jest zbudowana z danych w żądaniu HTTP lub nawet niestandardowych danych, które są dodawane do nagłówka HTTP, wiadomość może zawierać:
- Znacznik czasu: godzina wysłania żądania (UTC lub GMT)
- Czasownik HTTP: GET, POST, PUT, DELETE.
- przesłać dane i ciąg zapytania,
- URL
Pod maską uwierzytelnianie HMAC byłoby:
Konsument wysyła żądanie HTTP do serwera WWW, po zbudowaniu podpisu (dane wyjściowe skrótu hmac) szablon żądania HTTP:
User-Agent: {agent}
Host: {host}
Timestamp: {timestamp}
Authentication: {username}:{signature}
Przykład żądania GET:
GET /webapi.hmac/api/values
User-Agent: Fiddler
Host: localhost
Timestamp: Thursday, August 02, 2012 3:30:32 PM
Authentication: cuongle:LohrhqqoDy6PhLrHAXi7dUVACyJZilQtlDzNbLqzXlw=
Wiadomość do skrótu, aby uzyskać podpis:
GET\n
Thursday, August 02, 2012 3:30:32 PM\n
/webapi.hmac/api/values\n
Przykład żądania POST z ciągiem zapytania (poniższy podpis jest niepoprawny, tylko przykład)
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
Wiadomość do skrótu, aby uzyskać podpis
GET\n
Thursday, August 02, 2012 3:30:32 PM\n
/webapi.hmac/api/values\n
key1=value1&key2=value2&key3=value3
Należy pamiętać, że dane formularza i ciąg zapytania powinny być w porządku, więc kod na serwerze otrzymuje ciąg zapytania i dane formularza, aby zbudować poprawny komunikat.
Gdy żądanie HTTP przychodzi do serwera, wdrażany jest filtr akcji uwierzytelniania, który analizuje żądanie w celu uzyskania informacji: czasownik HTTP, znacznik czasu, identyfikator użytkownika, dane formularza i ciąg zapytania, a następnie na podstawie tych danych do zbudowania podpisu (użyj skrótu hmac) za pomocą klucza tajnego klucz (hashowane hasło) na serwerze.
Tajny klucz jest pobierany z bazy danych z nazwą użytkownika na żądanie.
Następnie kod serwera porównuje podpis na żądanie z podpisem zbudowanym; jeśli jest równy, uwierzytelnienie jest przekazywane, w przeciwnym razie nie powiedzie się.
Kod do budowy podpisu:
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;
}
Jak więc zapobiec atakowi powtórek?
Dodaj ograniczenie znacznika czasu, na przykład:
servertime - X minutes|seconds <= timestamp <= servertime + X minutes|seconds
(servertime: czas nadejścia żądania do serwera)
I buforuj podpis żądania w pamięci (użyj MemoryCache, należy zachować limit czasu). Jeśli następne żądanie zostanie opatrzone tym samym podpisem co poprzednie, zostanie odrzucone.
Kod demonstracyjny jest umieszczony tutaj:
https://github.com/cuongle/Hmac.WebApi