Identification Failures in Aspnet with Mutual Tls
Identification Failures in Aspnet with Mutual Tls
Identification failures occur when an application fails to properly establish and verify the identity of both the client and the server. In ASP.NET, enabling Mutual TLS (mTLS) means both parties present and validate certificates. When mTLS is configured incorrectly, the identity checks that should be enforced can be bypassed or misapplied, leading to authorization bypasses and request forgery.
In ASP.NET Core, mTLS is typically configured via Kestrel or via IIS/http.sys with client certificates required. A common misconfiguration is setting ClientCertificateMode to AllowAnonymous or NoCertificate in development-like settings that are mistakenly promoted to production. For example, if the server requests a client certificate but does not enforce validation, an attacker could connect without providing a valid client cert or with a self-signed cert that the server trusts unintentionally.
Another identification failure pattern is weak certificate validation logic. Custom certificate validation callbacks may check only the subject common name while ignoring the full chain, revocation status, or enhanced key usage. An attacker with a certificate issued by a compromised intermediate CA could pass such a weak check. Additionally, if the server does not validate the client certificate against a revocation list (CRL) or Online Certificate Status Protocol (OCSP), revoked or compromised client certificates remain accepted.
ASP.NET’s authentication middleware integrates with the server’s certificate validation. If developers use AuthenticationBuilder.AddCertificate without tightening the policy, the default policy may permit identities that should be rejected. For instance, relying on the certificate’s subject without validating the intended purpose (e.g., client authentication extended key usage) can allow non-client certificates to be accepted as identities.
Consider the following realistic ASP.NET Core configuration with mTLS. This example shows correct server-side settings that require and validate client certificates:
// Program.cs
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel(serverOptions =>
{
serverOptions.ListenAnyIP(5001, listenOptions =>
{
listenOptions.UseHttps(httpsOptions =>
{
httpsOptions.ClientCertificateMode = ClientCertificateMode.RequireCertificate;
httpsOptions.ServerCertificate = new X509Certificate2("server.pfx", "password");
httpsOptions.ClientCertificateValidation = (cert, chain, errors) =>
{
// Validate the chain and policy properly in production
if (errors != SslPolicyErrors.None)
{
return false;
}
// Example: ensure the client cert has the correct EKU for client auth
var eku = new Oid("1.3.6.1.5.5.7.3.2"); // Client Authentication
return cert.Extensions.OfType()
?.SelectMany(e => e.EnhancedKeyUsages.OfType())
.Any(ekuOid => ekuOid.Value == eku.Value) == true;
};
});
});
});
var app = builder.Build();
app.UseAuthentication();
app.UseAuthorization();
app.Run((context) => $"Hello, {context.Connection.ClientCertificate?.Subject ?? "Unknown"}");
app.Run();
Contrast this with a vulnerable configuration where client certificates are requested but not validated:
// Dangerous: does not validate client certificates properly
builder.WebHost.ConfigureKestrel(serverOptions =>
{
serverOptions.ListenAnyIP(5002, listenOptions =>
{
listenOptions.UseHttps(httpsOptions =>
{
httpsOptions.ClientCertificateMode = ClientCertificateMode.RequireCertificate;
httpsOptions.ServerCertificate = new X509Certificate2("server.pfx", "password");
// Weak validation: accepts any cert trusted by the system store
// without checking revocation or extended key usage
httpsOptions.ClientCertificateValidation = (cert, chain, errors) => true;
});
});
});
In the weak example, any client-supplied certificate accepted by the system store will pass, enabling an attacker with any valid (even revoked) client certificate to be identified as an authorized user. This directly maps to an Identification Failure: the application does not correctly verify the client’s identity. Attack patterns include presenting a stolen but valid client certificate, exploiting a CA that improperly issues client certificates, or leveraging a server that skips revocation checks.
Proper identification in mTLS requires strict validation: enforce certificate mode, validate the entire chain, check revocation, and verify extended key usage. Only then can the server reliably identify the client and prevent identification failures.
Mutual Tls-Specific Remediation in Aspnet
Remediation focuses on enforcing strict certificate validation and ensuring the server and client each verify the other’s identity. The following practices and code examples address the identification failures described above.
- Require client certificates and validate them rigorously: set
ClientCertificateMode.RequireCertificateand implement a validation callback that checks chain trust, revocation, and intended purpose. - Validate the certificate chain and revocation: use
X509Chainwith appropriate chain policy and enable revocation checks. - Check extended key usage: ensure the client certificate includes the Client Authentication EKU (OID 1.3.6.1.5.5.7.3.2).
- Do not rely solely on subject or thumbprint; use the certificate’s public key or a robust fingerprinting mechanism for authorized identities if needed, but always anchor to chain validation.
- Prefer configuration over custom validation when possible; if you must use custom validation, make it strict and well-audited.
Secure ASP.NET Core configuration example with chain and EKU validation:
// Program.cs — secure mTLS setup
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel(serverOptions =>
{
serverOptions.ListenAnyIP(5001, listenOptions =>
{
listenOptions.UseHttps(httpsOptions =>
{
httpsOptions.ClientCertificateMode = ClientCertificateMode.RequireCertificate;
httpsOptions.ServerCertificate = new X509Certificate2("server.pfx", "password");
httpsOptions.ClientCertificateValidation = (cert, chain, errors) =>
{
// 1. Basic chain and policy checks
if (errors != SslPolicyErrors.None)
{
return false;
}
// 2. Build and validate the chain with revocation checks
var chain2 = new X509Chain();
chain2.ChainPolicy.RevocationMode = X509RevocationMode.Online;
chain2.ChainPolicy.VerificationFlags = X509VerificationFlags.NoFlag;
chain2.ChainPolicy.ExtraStore.Add(new X509Certificate2("ca.cer"));
if (!chain2.Build(cert))
{
return false;
}
// 3. Check leaf certificate EKU for client authentication
var ekuOid = new Oid("1.3.6.1.5.5.7.3.2"); // Client Authentication
bool hasClientEku = cert.Extensions.OfType()
?.SelectMany(e => e.EnhancedKeyUsages.OfType())
.Any(oid => oid.Value == ekuOid.Value) == true;
if (!hasClientEku)
{
return false;
}
// Optional: additional policy checks, e.g., application-specific mappings
return true;
};
});
});
});
var app = builder.Build();
app.UseAuthentication();
app.UseAuthorization();
app.Run((context) => $"Authenticated client: {context.Connection.ClientCertificate?.Subject}");
app.Run();
Client-side mTLS example using HttpClient with a client certificate (for completeness, though identification failures are commonly server-side):
// Client example to present a certificate when calling an mTLS-enabled API
var handler = new HttpClientHandler();
handler.ClientCertificates.Add(new X509Certificate2("client.pfx", "clientPassword"));
// Important: ensure server certificate validation is not disabled in production
handler.ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator; // only for testing
using var client = new HttpClient(handler);
var response = await client.GetAsync("https://localhost:5001/secure");
By combining server-side enforcement with strict validation of chain revocation and EKU, you mitigate identification failures. This aligns with security practices expected in high-assurance scenarios and complements scans that check authentication and authorization controls.