Clickjacking in Aspnet with Hmac Signatures
Clickjacking in Aspnet with Hmac Signatures — how this specific combination creates or exposes the vulnerability
Clickjacking exploits user interaction by embedding a target site inside an invisible or misleading frame. In ASP.NET applications that use HMAC signatures to protect state-changing requests (e.g., anti-forgery tokens or form-hmac patterns), clickjacking can still occur if the HMAC is computed only on the server-side payload and not tied to frame-defeting defenses. An attacker can load the legitimate page within a frame, overlay interactive elements (like buttons or links) positioned precisely over expected actions (such as "Approve" or "Transfer"). When the user interacts, the forged click is sent with the victim’s valid HMAC-signed request because the signature covers the request parameters and possibly an anti-forgery token, but does not inherently prevent the request from being embedded or submitted from a hidden context.
ASP.NET’s typical HMAC implementation for anti-forgery (e.g., using AntiForgeryToken with custom storage or ValidateAntiForgeryToken attribute) ensures request integrity but does not enforce same-origin framing rules. If the response lacks Content-Security-Policy frame-ancestors or X-Frame-Options, the page remains embeddable. The HMAC signature validates the request came from the application and was not tampered with, yet it does not stop a malicious page from causing the user’s browser to make a forged request within that embedded context. This creates a scenario where the HMAC-protected request is still issued under coercion, leading to unauthorized actions despite integrity checks. The vulnerability is not in the HMAC algorithm itself but in the absence of frame-protection headers and UI-redirect defenses that complement the cryptographic integrity check.
For example, an ASP.NET MVC action decorated with [ValidateAntiForgeryToken] and using HMAC-based token generation can be targeted. The attacker crafts a page with a form that mirrors the target action’s endpoint and fields, overlays a transparent button over a visible element to capture clicks, and submits the form. The browser includes the anti-forgery cookie and the HMAC-signed token in the request, making the server-side validation pass. Without additional protections like X-Frame-Options or Content-Security-Policy, the request is processed. This underscores that HMAC signatures protect integrity, not context; they must be paired with frame-protection mechanisms to mitigate clickjacking.
Hmac Signatures-Specific Remediation in Aspnet — concrete code fixes
Remediation combines HMAC integrity with frame-protection headers and anti-clickjacking UI practices. In ASP.NET, configure anti-clickjacking headers and ensure HMAC-signed requests are only accepted in a first-party context. Below are concrete code examples.
1. Enabling Anti-Forgery with HMAC and Frame Protection in ASP.NET Core
Use AddAntiForgery with custom options and enforce same-site and frame-ancestors policies.
// Program.cs or Startup configuration
using Microsoft.AspNetCore.Antiforgery;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
var builder = WebApplication.CreateBuilder(args);
// Configure anti-forgery to use cookies and HMAC-like validation (framework-managed signature)
builder.Services.AddAntiforgery(options =>
{
options.HeaderName = "XSRF-TOKEN";
options.Cookie.Name = "XSRF-COOKIE";
options.Cookie.SameSite = SameSiteMode.Strict;
options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
options.RequireSameSiteVerification = true;
});
var app = builder.Build();
// Apply CSP and X-Frame-Options globally
app.Use(async (context, next) =>
{
context.Response.Headers.Add("Content-Security-Policy", "frame-ancestors 'self'");
context.Response.Headers.Add("X-Frame-Options", "DENY");
await next();
});
app.UseAntiforgery();
app.MapPost("/transfer", (IAntiforgery antiForgery, HttpContext http) =>
{
var tokens = antiForgery.GetAndStoreTokens(http);
// Process transfer; tokens validated automatically via [ValidateAntiForgeryToken]
return Results.Ok();
}).RequireAuthorization().WithMetadata(new AutoValidateAntiforgeryTokenAttribute());
app.Run();
2. HMAC Signature Generation and Verification with Frame Checks in ASP.NET Framework (MVC)
Generate and validate HMAC for critical parameters and enforce same-origin via headers in responses.
// HmacUtility.cs
using System;
using System.Security.Cryptography;
using System.Text;
public static class HmacUtility
{
private static readonly byte[] Key = Convert.FromBase64String("YOUR_BASE64_KEY_32_BYTES_LENGTH_HERE_EqU1a2b3c4d5e6f7g8h9i0j1k2l3m4n5o6=");
public static string ComputeHmac(string data)
{
using var hmac = new HMACSHA256(Key);
var hash = hmac.ComputeHash(Encoding.UTF8.GetBytes(data));
return Convert.ToBase64String(hash);
}
public static bool VerifyHmac(string data, string signature)
{
var computed = ComputeHmac(data);
return computed == signature;
}
}
// In a controller (e.g., TransferController.cs)
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Transfer(TransferModel model, string requestHmac)
{
// Reconstruct the signed payload (example: concatenation of key fields)
var payload = $"{model.AccountId}|{model.Amount}|{model.Timestamp}";
if (!HmacUtility.VerifyHmac(payload, requestHmac))
{
return new HttpStatusCodeResult(403, "Invalid signature");
}
// Proceed with business logic
return RedirectToAction("Confirmation");
}
// In Global.asax or an ActionFilter to enforce frame protection
protected void Application_BeginRequest(object sender, EventArgs e)
{
Context.Response.Headers.Add("Content-Security-Policy", "frame-ancestors 'self'");
Context.Response.Headers.Add("X-Frame-Options", "DENY");
}
3. SPA or API Client Guidance
When consuming ASP.NET endpoints from JavaScript, ensure anti-forgery tokens are read from cookies and sent in headers, and that the site is not embedded inadvertently.
// Example: Fetch with anti-forgery token read from cookie and HMAC-signed body
async function submitTransfer(data) {
const token = getCookie('XSRF-COOKIE'); // read cookie set by server
const payload = JSON.stringify(data);
// Optionally compute HMAC on client if required by server scheme
const response = await fetch('/transfer', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'XSRF-TOKEN': token
},
body: payload,
credentials: 'same-origin' // ensures cookies only sent to same origin
});
return response.json();
}
These measures ensure HMAC-signed requests remain trustworthy by preventing them from being triggered cross-origin via clickjacking techniques.