Adding HMAC (Hash-based Message Authentication Code) authentication to an ASP.NET Core application can help ensure that requests are authenticated and have not been tampered with. You can implement this as a custom middleware.
The Middleware Class
The middleware will extract the necessary information from the request headers (e.g., Authorization header), calculate the HMAC signature, and compare it to the one provided by the client.
using System.Security.Cryptography;
using System.Text;
using Microsoft.Extensions.Primitives;
public class HmacAuthenticationMiddleware(RequestDelegate next, string secretKey)
{
private readonly RequestDelegate next = next;
private readonly string secretKey = secretKey;
public async Task Invoke(HttpContext context)
{
// Extract the HMAC signature from the Authorization header
if (!context.Request.Headers.TryGetValue("Authorization", out StringValues authHeader))
{
context.Response.StatusCode = 401;
await context.Response.WriteAsync("Missing Authorization Header");
return;
}
// The Authorization header should be in the format: HMAC <signature>
string[] authParts = authHeader.ToString().Split(' ');
if (authParts.Length != 2 || authParts[0] != "HMAC")
{
context.Response.StatusCode = 401;
await context.Response.WriteAsync("Invalid Authorization Header Format");
return;
}
string providedSignature = authParts[1];
// Calculate the HMAC of the request
string calculatedSignature = await ComputeHmacSignature(context, secretKey);
// Compare the provided signature with the calculated one
if (!providedSignature.Equals(calculatedSignature, StringComparison.OrdinalIgnoreCase))
{
context.Response.StatusCode = 401;
await context.Response.WriteAsync("Invalid Signature");
return;
}
// Call the next middleware in the pipeline
await next(context);
}
private static async Task<string> ComputeHmacSignature(HttpContext context, string secretKey)
{
// Read the request content
context.Request.EnableBuffering();
var requestBody = await new StreamReader(context.Request.Body).ReadToEndAsync();
context.Request.Body.Position = 0;
// Compute the HMAC SHA256 hash
using var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(secretKey));
byte[] hash = hmac.ComputeHash(Encoding.UTF8.GetBytes(requestBody));
return Convert.ToBase64String(hash);
}
}
Extension Method for Middleware
n .NET, extension methods for middleware registration encapsulate setup details, simplifying Startup.cs and promoting clean, reusable code. This convention hides complexity, providing a fluent and consistent way to add middleware to the request pipeline.
public static class HmacAuthenticationMiddlewareExtensions
{
public static IApplicationBuilder UseHmacAuthentication(this IApplicationBuilder app, string secretKey)
{
ArgumentNullException.ThrowIfNull(app);
return app.UseMiddleware<HmacAuthenticationMiddleware>(secretKey);
}
}
Register the Middleware
Register the middleware in your Program.cs or Startup.cs file. Use the HMAC secret key generated by Cubu.