Dns Rebinding in Aspnet with Bearer Tokens
Dns Rebinding in Aspnet with Bearer Tokens — how this specific combination creates or exposes the vulnerability
DNS rebinding is a client-side attack that manipulates DNS responses to make a browser send requests to an internal network address that the attacker does not directly control. In an ASP.NET application that relies on bearer tokens for authorization, combining a rebinding-capable domain with token handling on the server can expose privileged internal endpoints to a remote attacker.
Consider an ASP.NET Core web application that validates a bearer token from an Authorization header and then forwards requests to an internal service, such as a diagnostics or management API bound to 127.0.0.1. The attacker registers a domain (e.g., evil.example) pointing to an external IP they control. Through a rebinding mechanism—often involving time-based DNS they can control—the client resolves the attacker’s external IP initially to pass same-origin checks, then switches to an internal IP like 127.0.0.1 or 10.0.0.1. Because the browser includes cookies and authorization headers (including bearer tokens) for the domain, the request to the internal endpoint is authenticated as the victim user.
In this scenario, the bearer token is not the initial authentication mechanism the attacker steals; instead, the token represents the victim’s authenticated session. The attacker exploits the trust placed in that token by the ASP.NET backend, which may assume that requests with a valid token are safe to forward internally. If the application does not validate the target host or enforce strict origin checks, the rebinding-enabled request can reach internal management endpoints, change configuration, or extract sensitive data. This is especially dangerous when the backend uses bearer token introspection or relies on token claims without additional network-level validation, because the token remains valid while the network path is hijacked.
The attack chain typically involves a malicious webpage that uses JavaScript to repeatedly resolve a hostname and send authenticated requests to what appears to be a public endpoint but resolves internally. In ASP.NET, if the application integrates bearer tokens with HTTP client calls to internal APIs without verifying the resolved IP or hostname, the token effectively becomes a credential for the attacker’s chosen internal target. Common frameworks and libraries used in ASP.NET may not inherently prevent requests to loopback or private IPs when authorization headers are present, enabling the rebinding to succeed where naive trust in tokens exists.
To detect such issues, scanning with an approach that inspects both API specifications and runtime behavior is useful. The OpenAPI/Swagger analysis performed by tools like middleBrick can reveal endpoints that accept bearer tokens and whether they reference localhost or private IPs in server variables or descriptions, while runtime checks can surface unexpected internal resolution patterns. While scanners do not modify code, they highlight risky design choices—such as forwarding authenticated requests to internal services—that should be reviewed to mitigate DNS rebinding in combination with bearer token authentication.
Bearer Tokens-Specific Remediation in Aspnet — concrete code fixes
Remediation focuses on preventing unauthorized internal access and ensuring bearer tokens are not implicitly trusted for network-level decisions. Below are concrete code examples for ASP.NET Core that demonstrate secure practices.
1. Validate request hostnames and reject private IPs
Explicitly check the incoming request host and reject connections that resolve to private or loopback addresses when the request requires high assurance. This prevents rebinding from reaching internal endpoints even when a valid bearer token is present.
using Microsoft.AspNetCore.Http;
using System.Net;
public class PrivateHostFilterMiddleware
{
private readonly RequestDelegate _next;
public PrivateHostFilterMiddleware(RequestDelegate next) => _next = next;
public async Task InvokeAsync(HttpContext context)
{
var host = context.Request.Host;
if (IPAddress.TryParse(host.Host, out var ip))
{
if (IPAddress.IsLoopback(ip) || ip.IsPrivate())
{
context.Response.StatusCode = StatusCodes.Status403Forbidden;
await context.Response.WriteAsync("Forbidden: private IP access not allowed.");
return;
}
}
await _next(context);
}
}
// Extension for private IP detection
public static class IPAddressExtensions
{
public static bool IsPrivate(this IPAddress address)
{
if (address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
{
byte[] bytes = address.GetAddressBytes();
// 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16
if (bytes[0] == 10) return true;
if (bytes[0] == 172 && bytes[1] >= 16 && bytes[1] <= 31) return true;
if (bytes[0] == 192 && bytes[1] == 168) return true;
}
return false;
}
}
// In Startup.cs or Program.cs
app.UseMiddleware<PrivateHostFilterMiddleware>();
2. Validate anti-rebinding headers and referrer where applicable
Use the Origin and Referer headers as an additional layer to detect cross-origin requests that may be manipulated via DNS. Reject requests that do not match expected origins, especially for sensitive operations involving bearer tokens.
using Microsoft.AspNetCore.Http;
using System.Linq;
public class OriginValidationMiddleware
{
private readonly RequestDelegate _next;
private readonly string[] _allowedOrigins;
public OriginValidationMiddleware(RequestDelegate next, string[] allowedOrigins) =
(_next, _allowedOrigins) = (next, allowedOrigins);
public async Task InvokeAsync(HttpContext context)
{
if (context.Request.Headers.TryGetValue("Origin", out var origin))
{
if (!_allowedOrigins.Contains(origin))
{
context.Response.StatusCode = StatusCodes.Status403Forbidden;
await context.Response.WriteAsync("Forbidden: Origin not allowed.");
return;
}
}
await _next(context);
}
}
// In Program.cs
var allowedOrigins = new[] { "https://trusted.example" };
app.UseMiddleware<OriginValidationMiddleware>(allowedOrigins);
3. Secure HTTP client calls that use bearer tokens
If your ASP.NET backend makes outgoing HTTP calls using bearer tokens, avoid using loopback or private targets derived from user input. Explicitly configure the base address and validate hostnames before sending requests.
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
public class SecureHttpClient
{
private readonly HttpClient _client;
public SecureHttpClient(HttpClient client)
{
_client = client;
_client.BaseAddress = new System.Uri("https://api.trusted.example");
_client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", "");
}
public async Task GetDataAsync()
{
// Ensure the request targets an explicitly allowed host
var response = await _client.GetAsync("/v1/resource");
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
}
4. Combine bearer token validation with host checks in authorization policies
Use ASP.NET Core’s policy-based authorization to require that the request host matches an allowed set, in addition to validating the bearer token. This ensures that even if a token is valid, requests to internal endpoints are denied when they originate from a rebinding-capable domain.
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using System.Threading.Tasks;
public class HostAuthorizationHandler : IAuthorizationHandler
{
public Task HandleAsync(AuthorizationHandlerContext context)
{
var httpContext = context.Resource as HttpContext;
if (httpContext == null) return Task.CompletedTask;
var host = httpContext.Request.Host.Host;
if (host == "trusted.example")
{
context.Succeed(context.Requirements.First());
}
else
{
context.Fail();
}
return Task.CompletedTask;
}
}
These examples illustrate how to reduce the attack surface when bearer tokens are used in ASP.NET applications. Defense in depth—validating hosts, avoiding implicit trust in tokens for internal calls, and enforcing strict origin checks—helps prevent successful DNS rebinding attacks.