Excessive Data Exposure in Aspnet with Mutual Tls
Excessive Data Exposure in Aspnet with Mutual Tls
Excessive Data Exposure occurs when an API returns more information than necessary, such as full database rows, internal identifiers, or sensitive fields that should remain hidden. In an ASP.NET API, this often surfaces through endpoints that serialize entire domain models directly to JSON without explicit filtering. When Mutual TLS is used for transport-layer authentication, the presence of mTLS may create a false sense of security. Operators assume that because client certificates are required, the data exposure surface is reduced. In practice, mTLS secures the channel but does nothing to limit what the server returns to an authenticated and authorized client.
Consider an ASP.NET Core Web API that uses Mutual TLS to authenticate clients. The endpoint might simply return a full EF Core entity:
// Example: excessive data exposure
[ApiController]
[Route("api/users")]
public class UsersController : ControllerBase
{
private readonly AppDbContext _context;
public UsersController(AppDbContext context) => _context = context;
[HttpGet("{id}")]
public async Task<ActionResult<User>> GetUser(Guid id)
{
var user = await _context.Users.FindAsync(id);
if (user == null) return NotFound();
return Ok(user); // returns all fields, including sensitive ones
}
}
Even with Mutual TLS, this endpoint may leak internal properties such as PasswordHash, TwoFactorSecret, or InternalTenantId. Attackers who compromise a client certificate or exploit a misconfigured authorization policy can enumerate or infer additional data. Furthermore, reflection-based serializers used by System.Text.Json or Newtonsoft.Json can expose nested objects that were not intended for the client, including related entities loaded via lazy or eager navigation properties.
In the context of the 12 security checks run by middleBrick, Excessive Data Exposure is evaluated by comparing the documented response schema (such as an OpenAPI spec) against runtime observations. If the runtime data includes fields that are not documented or that should be restricted by role or scope, a finding is generated. This check is independent of Mutual TLS because the scanner validates what is returned, not how the connection was secured.
To illustrate the intersection with Mutual TLS, an ASP.NET app can be configured to require client certificates, but if the controller does not apply field-level filtering or view models, the data exposure persists:
// Startup configuration enforcing Mutual TLS (no data filtering)
builder.Services.AddAuthentication(CertificateAuthenticationDefaults.AuthenticationScheme)
.AddCertificate(options =>
{
options.AllowedCertificateTypes = CertificateTypes.All;
options.RevocationMode = X509RevocationMode.Online;
});
builder.Services.AddAuthorization();
// ...
app.UseAuthentication();
app.UseAuthorization();
The configuration above ensures that only clients with valid certificates can connect, yet it does not reduce the risk of returning excessive fields. The remediation is to introduce explicit projection, such as mapping entities to DTOs or using Select/SelectQuery to limit returned data, regardless of the transport security.
Mutual Tls-Specific Remediation in Aspnet
Remediation focuses on ensuring that even when Mutual TLS is enforced, responses contain only necessary data. This involves combining certificate-based authentication with disciplined serialization practices. Below are concrete code examples for an ASP.NET Core API that uses Mutual TLS and returns minimal, safe data.
1. Configure Mutual TLS in Program.cs:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddAuthentication(CertificateAuthenticationDefaults.AuthenticationScheme)
.AddCertificate(options =>
{
options.AllowedCertificateTypes = CertificateTypes.All;
options.RevocationMode = X509RevocationMode.Online;
options.RemoteCertificateValidationCallback = (sender, cert, chain, errors) =>
{
// Additional validation, e.g., thumbprint checks
return errors == SslPolicyErrors.None;
};
});
builder.Services.AddAuthorization();
var app = builder.Build();
app.UseAuthentication();
app.UseAuthorization();
2. Define a DTO that excludes sensitive fields:
public class UserProfileDto
{
public Guid Id { get; set; }
public string Email { get; set; } = string.Empty;
public string Name { get; set; } = string.Empty;
// Do not include PasswordHash, TwoFactorSecret, or internal flags
}
3. Map the entity to the DTO in the controller:
[ApiController]
[Route("api/users")]
public class UsersController : ControllerBase
{
private readonly AppDbContext _context;
private readonly IMapper _mapper; // assuming AutoMapper or similar
public UsersController(AppDbContext context, IMapper mapper)
{
_context = context;
_mapper = mapper;
}
[HttpGet("{id}")]
public async Task<ActionResult<UserProfileDto>> GetUser(Guid id)
{
var user = await _context.Users.FindAsync(id);
if (user == null) return NotFound();
var dto = _mapper.Map<UserProfileDto>(user);
return Ok(dto);
}
}
4. Alternatively, use a manual projection to avoid reflection-based serialization issues:
[HttpGet("{id}")]
public async Task<ActionResult<UserProfileDto>> GetUserManual(Guid id)
{
var dto = await _context.Users
.Where(u => u.Id == id)
.Select(u => new UserProfileDto
{
Id = u.Id,
Email = u.Email,
Name = u.Name
})
.FirstOrDefaultAsync();
if (dto == null) return NotFound();
return Ok(dto);
}
These examples show that Mutual TLS secures the channel, but data exposure controls must be implemented at the application layer. By returning DTOs and avoiding full entity serialization, you reduce the attack surface even when client certificates are in use.
Related CWEs: propertyAuthorization
| CWE ID | Name | Severity |
|---|---|---|
| CWE-915 | Mass Assignment | HIGH |