Excessive Data Exposure in Actix with Mutual Tls
Excessive Data Exposure in Actix with Mutual Tls
Excessive Data Exposure occurs when an API returns more data than the client needs, and this risk can be amplified when Mutual TLS (mTLS) is used without careful attention to authorization and data minimization. In Actix, mTLS ensures both client and server authenticate each other with certificates, but it does not by itself limit what data a successfully authenticated client can see. If endpoints return full database records, verbose error details, or sensitive fields such as internal IDs, password hashes, or tokens, mTLS alone will not prevent exposure.
Consider an Actix service that uses mTLS for transport-layer authentication and then retrieves a user profile by ID. If the handler deserializes the record and returns the entire structure directly as JSON, fields like internal_role, password_hash, or api_key may be included unintentionally. This becomes a data exposure issue because the client receives data it should not have, even though the TLS handshake verified identity. The problem is not mTLS but the lack of output filtering and the absence of per-action authorization checks.
Additionally, mTLS can create a false sense of security. Teams may assume that because certificates are required, all requests are from trusted clients, and therefore skip checks like object-level authorization (e.g., ensuring user A cannot access user B’s resources). In Actix, if route parameters such as user_id are taken from the path or claims without verifying that the authenticated peer is allowed to view that specific resource, BOLA or IDOR-style exposure occurs. For example, an endpoint like GET /users/{user_id} that trusts the mTLS certificate but does not compare the certificate’s subject to the requested user_id can leak one user’s data to another.
Over-fetching and under-filtering commonly appear when using serialization libraries that include all struct fields by default. In Actix, if a handler returns a struct that maps to a database row, fields that should be omitted in certain contexts will still be serialized and sent. This is a data exposure issue even when mTLS is enforced, because the transport is secure but the payload contains unnecessary sensitive information. Error responses can also expose data; detailed database errors or stack traces returned to the client may reveal schema details or internal paths, compounding the exposure.
To assess this with middleBrick, scans validate that responses do not include sensitive fields such as passwords, tokens, or internal identifiers unless explicitly required. The tool checks whether authorization is applied at the field or record level and whether error handling avoids verbose details. These checks complement mTLS by focusing on application-layer data handling rather than transport security.
Mutual Tls-Specific Remediation in Actix
Remediation focuses on ensuring that mTLS is used for authentication while applying strict data minimization and authorization. In Actix, you should explicitly verify the client certificate subject against the requested resource and filter response fields based on context and user permissions.
Below is an example of an Actix web server configured for mTLS, with client identity extracted and used in authorization. The handler checks that the authenticated peer is allowed to access the requested resource before returning a filtered response.
use actix_web::{web, App, HttpResponse, HttpServer, Responder};
use actix_web::http::header::HeaderValue;
use openssl::ssl::{SslAcceptor, SslFiletype, SslMethod};
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)]
struct UserProfile {
user_id: String,
username: String,
// Include only non-sensitive fields for general queries
display_name: String,
email: String,
}
async fn get_user_profile(
path: web::Path,
req: actix_web::HttpRequest,
) -> impl Responder {
// Extract client certificate subject from request extensions
let peer_id = req.extensions()
.get::()
.map(|s| s.as_str())
.unwrap_or("");
let requested_user_id = path.into_inner();
// Enforce object-level authorization: client can only access their own profile
if peer_id != requested_user_id {
return HttpResponse::Forbidden().json(serde_json::json!({
"error": "access_denied",
"message": "You can only access your own profile"
}));
}
// Simulated database fetch; in practice, map and filter fields
let full_record = db_get_user_by_id(&requested_user_id);
// Filter to safe fields to prevent excessive exposure
let safe_profile = UserProfile {
user_id: full_record.user_id,
username: full_record.username,
display_name: full_record.display_name,
email: full_record.email,
};
HttpResponse::Ok().json(safe_profile)
}
fn db_get_user_by_id(user_id: &str) -> FullUserRecord {
// Placeholder: replace with actual DB query
FullUserRecord {
user_id: user_id.to_string(),
username: "alice".to_string(),
display_name: "Alice".to_string(),
email: "[email protected]".to_string(),
password_hash: "hashed_secret".to_string(), // Should not be serialized
api_key: "internal_key_123".to_string(), // Should not be serialized
internal_role: "admin".to_string(), // Should not be serialized
}
}
struct FullUserRecord {
user_id: String,
username: String,
display_name: String,
email: String,
password_hash: String,
api_key: String,
internal_role: String,
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
let mut builder = SslAcceptor::mozilla_server(SslMethod::tls()).unwrap();
builder.set_private_key_file("key.pem", SslFiletype::PEM).unwrap();
builder.set_certificate_chain_file("cert.pem").unwrap();
// Require and verify client certificates
builder.set_verify(openssl::ssl::SslVerifyMode::PEER | openssl::ssl::SslVerifyMode::FAIL_IF_NO_PEER_CERT);
builder.set_ca_file("ca.pem").unwrap();
HttpServer::new(move || {
App::new()
.wrap(actix_web_httpauth::extractors::ssl::SslRequest::new())
.route("/users/{user_id}", web::get().to(get_user_profile))
})
.bind_openssl("127.0.0.1:8443", builder)?
.run()
.await
}
Key points in this remediation:
- mTLS is enforced at the server level via OpenSSL configuration, requiring client certificates.
- The client certificate subject is extracted and mapped to an identity (e.g.,
peer_id) and used for authorization.The handler implements object-level checks so a client cannot access another user’s profile by changing the path parameter. - The response is explicitly filtered to a safe subset of fields, preventing exposure of passwords, API keys, or internal roles. This addresses excessive data exposure regardless of the mTLS setup.
For production, rotate certificates regularly and ensure the CA verification chain is properly configured. Combine this with input validation on path and query parameters to further reduce risk.
Related CWEs: propertyAuthorization
| CWE ID | Name | Severity |
|---|---|---|
| CWE-915 | Mass Assignment | HIGH |