Обновить:
Я добавил эту ссылку в свой другой ответ, как использовать аутентификацию JWT для ASP.NET Web API здесь для всех, кто интересуется JWT.
Нам удалось применить аутентификацию HMAC для защиты веб-API, и все заработало нормально. HMAC-аутентификация использует секретный ключ для каждого потребителя, который, как пользователь, так и сервер, знают, что hmac хэширует сообщение, следует использовать HMAC256. В большинстве случаев хешированный пароль потребителя используется в качестве секретного ключа.
Сообщение обычно строится из данных в HTTP-запросе или даже из пользовательских данных, которые добавляются в HTTP-заголовок. Сообщение может содержать:
- Отметка времени: время отправки запроса (UTC или GMT)
- HTTP-глагол: GET, POST, PUT, DELETE.
- разместить данные и строку запроса,
- URL
Под капотом аутентификация HMAC будет:
Потребитель отправляет HTTP-запрос на веб-сервер, после построения подписи (вывод хеша hmac) шаблон HTTP-запроса:
User-Agent: {agent}
Host: {host}
Timestamp: {timestamp}
Authentication: {username}:{signature}
Пример для запроса GET:
GET /webapi.hmac/api/values
User-Agent: Fiddler
Host: localhost
Timestamp: Thursday, August 02, 2012 3:30:32 PM
Authentication: cuongle:LohrhqqoDy6PhLrHAXi7dUVACyJZilQtlDzNbLqzXlw=
Сообщение для хеширования для получения подписи:
GET\n
Thursday, August 02, 2012 3:30:32 PM\n
/webapi.hmac/api/values\n
Пример запроса POST со строкой запроса (подпись ниже не верна, просто пример)
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
Сообщение в хеш для получения подписи
GET\n
Thursday, August 02, 2012 3:30:32 PM\n
/webapi.hmac/api/values\n
key1=value1&key2=value2&key3=value3
Обратите внимание, что данные формы и строка запроса должны располагаться по порядку, поэтому код на сервере получает строку запроса и данные формы для построения правильного сообщения.
Когда на сервер поступает HTTP-запрос, для анализа запроса внедряется фильтр действий аутентификации: HTTP-глагол, временная метка, uri, данные формы и строка запроса, а затем на их основе создается сигнатура (используется хэш hmac) с секретом. ключ (хешированный пароль) на сервере.
Секретный ключ получен из базы данных с именем пользователя по запросу.
Затем код сервера сравнивает подпись на запросе с созданной подписью; если равно, аутентификация пройдена, в противном случае она не удалась.
Код для построения подписи:
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;
}
Итак, как предотвратить повторную атаку?
Добавьте ограничение для отметки времени, что-то вроде:
servertime - X minutes|seconds <= timestamp <= servertime + X minutes|seconds
(время сервера: время поступления запроса на сервер)
И, кешировать подпись запроса в памяти (используйте MemoryCache, следует ограничивать время). Если следующий запрос приходит с той же подписью, что и предыдущий, он будет отклонен.
Демо-код приведен здесь:
https://github.com/cuongle/Hmac.WebApi