Actualizar:
He agregado este enlace a mi otra respuesta sobre cómo usar la autenticación JWT para la API web ASP.NET aquí para cualquier persona interesada en JWT.
Hemos logrado aplicar la autenticación HMAC para asegurar la API web, y funcionó bien. La autenticación HMAC usa una clave secreta para cada consumidor que tanto el consumidor como el servidor conocen para que hmac envíe un mensaje, se debe usar HMAC256. La mayoría de los casos, la contraseña hash del consumidor se utiliza como clave secreta.
El mensaje normalmente se crea a partir de datos en la solicitud HTTP, o incluso datos personalizados que se agregan al encabezado HTTP, el mensaje puede incluir:
- Marca de tiempo: hora en que se envía esa solicitud (UTC o GMT)
- Verbo HTTP: GET, POST, PUT, DELETE.
- publicar datos y consultar cadena,
- URL
Bajo el capó, la autenticación HMAC sería:
El consumidor envía una solicitud HTTP al servidor web, después de construir la firma (salida de hmac hash), la plantilla de solicitud HTTP:
User-Agent: {agent}
Host: {host}
Timestamp: {timestamp}
Authentication: {username}:{signature}
Ejemplo de solicitud GET:
GET /webapi.hmac/api/values
User-Agent: Fiddler
Host: localhost
Timestamp: Thursday, August 02, 2012 3:30:32 PM
Authentication: cuongle:LohrhqqoDy6PhLrHAXi7dUVACyJZilQtlDzNbLqzXlw=
El mensaje a hash para obtener la firma:
GET\n
Thursday, August 02, 2012 3:30:32 PM\n
/webapi.hmac/api/values\n
Ejemplo de solicitud POST con cadena de consulta (la firma a continuación no es correcta, solo un ejemplo)
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
El mensaje a hash para obtener firma
GET\n
Thursday, August 02, 2012 3:30:32 PM\n
/webapi.hmac/api/values\n
key1=value1&key2=value2&key3=value3
Tenga en cuenta que los datos del formulario y la cadena de consulta deben estar en orden, por lo que el código del servidor obtiene la cadena de consulta y los datos del formulario para generar el mensaje correcto.
Cuando la solicitud HTTP llega al servidor, se implementa un filtro de acción de autenticación para analizar la solicitud para obtener información: verbo HTTP, marca de tiempo, uri, datos de formulario y cadena de consulta, luego se basa en estos para construir la firma (use hash hmac) con el secreto clave (contraseña hash) en el servidor.
La clave secreta se obtiene de la base de datos con el nombre de usuario en la solicitud.
Luego, el código del servidor compara la firma en la solicitud con la firma construida; si es igual, se pasa la autenticación; de lo contrario, falla.
El código para construir la firma:
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;
}
Entonces, ¿cómo evitar el ataque de repetición?
Agregue restricción para la marca de tiempo, algo como:
servertime - X minutes|seconds <= timestamp <= servertime + X minutes|seconds
(tiempo de servicio: hora de solicitud que llega al servidor)
Y, guarde en caché la firma de la solicitud en la memoria (use MemoryCache, debe mantenerse en el límite de tiempo). Si la siguiente solicitud viene con la misma firma que la solicitud anterior, será rechazada.
El código de demostración se pone como aquí:
https://github.com/cuongle/Hmac.WebApi