Insufficient Logging in Actix with Mutual Tls
Insufficient Logging in Actix with Mutual Tls — how this specific combination creates or exposes the vulnerability
Insufficient logging in an Actix web service using mutual TLS (mTLS) creates blind spots that hinder detection, investigation, and compliance. With mTLS, the server authenticates the client via a client certificate, but if request and security events are not recorded in detail, you lose visibility into who accessed which endpoint and whether the presented certificate was valid, revoked, or missing.
In an mTLS-enabled Actix service, the TLS layer terminates the connection and performs certificate validation before requests reach Actix handlers. If logging is insufficient, you may know that a request arrived, but you cannot reliably correlate it with a specific certificate subject, serial number, or Common Name (CN). This matters for detecting credential misuse, replay attacks, or stolen certificates, and it complicates forensic investigations after a breach. Without structured logs that include the mTLS verification result, you cannot reliably assert whether a given request was authenticated by the server or merely reached the endpoint over a terminated TLS session.
Additionally, insufficient logging often omits critical metadata such as the TLS cipher suite, negotiated protocol version, and certificate verification errors. In regulated environments, frameworks like OWASP API Top 10 and standards such as PCI-DSS require audit trails for authentication events; without them, compliance evidence is incomplete. In an mTLS context, this means you cannot demonstrate which clients were authorized, whether certificate revocation checks (CRL/OCSP) succeeded, or whether unexpected fallback behavior occurred.
The risk is compounded when Actix applications also integrate with backend services or message queues, because cross-service calls may not propagate the identity extracted from the client certificate. If logs do not capture the mapped identity or the certificate attributes used for authorization decisions (e.g., mapping CN to roles), you lose traceability from edge to service. This gap can delay detection of privilege escalation attempts or BOLA/IDOR patterns that exploit weak identity binding.
middleBrick can help surface these gaps by scanning your unauthenticated API surface and correlating findings with logging and authentication configurations. Its checks include authentication, authentication anomalies, and data exposure, which can highlight endpoints where mTLS is not enforced or where logs lack sufficient detail to support auditability.
Mutual Tls-Specific Remediation in Actix — concrete code fixes
To address insufficient logging in Actix with mTLS, enrich logs with mTLS metadata and ensure certificate validation outcomes are recorded. Below are concrete, syntactically correct examples that show how to configure mTLS in Actix using the native Rust TLS features and how to log key certificate details.
1. Configure mTLS in Actix with rustls
Use rustls to require client authentication and extract peer certificates into request extensions for logging. This example sets up an Actix server that requires client certificates and logs the subject and verification status.
use actix_web::{web, App, HttpServer, Responder, HttpRequest};
use actix_web::dev::ServiceRequest;
use actix_web::middleware::Logger;
use std::sync::Arc;
use rustls::{ServerConfig, Certificate, PrivateKey};
use rustls::pki_types::{CertificateDer, PrivateKeyDer, UnixTime};
use std::io::{BufReader};
use std::fs::File;
use log::info;
async fn index(req: HttpRequest) -> impl Responder {
// Extract peer certs from request extensions (populated by custom middleware)
let certs = req.extensions().get::>().map(|c| c.len());
info!("Request served. TLS client certs: {:?}", certs);
"Hello from mTLS-enabled Actix service"
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
// Initialize logger to capture structured logs
env_logger::init();
// Load server certificate and key
let cert_file = &mut BufReader::new(File::open("server-cert.pem").expect("cannot open cert"));
let key_file = &mut BufReader::new(File::open("server-key.pem").expect("cannot open key"));
let cert_chain = rustls_pemfile::certs(cert_file).collect::, _>>().unwrap();
let mut keys = rustls_pemfile::pkcs8_private_keys(key_file).collect::, _>>().unwrap();
// Configure client authentication
let mut server_config = ServerConfig::builder()
.with_safe_defaults()
.with_no_client_auth() // start without client auth
.with_single_cert(cert_chain, keys.remove(0))
.expect("invalid certs or key");
// Require client authentication by providing trusted CA roots
let mut client_root_store = rustls::RootCertStore::empty();
let mut ca_file = BufReader::new(File::open("ca-cert.pem").expect("cannot open CA cert"));
let ca_certs = rustls_pemfile::certs(&mut ca_file).collect::, _>>().unwrap();
for cert in ca_certs {
client_root_store.add(&CertificateDer::from(cert)).expect("invalid CA cert");
}
server_config.client_auth_root_subjects = Some(client_root_store);
server_config.client_auth_mandatory = true;
HttpServer::new(move || {
App::new()
.wrap(Logger::default())
.wrap(MtlsLogger) // custom middleware to extract certs
.route("/", web::get().to(index))
})
.bind_rustls_0_23_0(([127, 0, 0, 1], 8080), server_config)?
.run()
.await
}
2. Custom middleware to extract and log certificate details
Implement middleware that reads the peer certificate chain from the TLS connection, stores it in the request extension, and logs relevant fields for auditability.
use actix_web::{Error, dev::{ServiceRequest, ServiceResponse}};
use actix_web::body::BoxBody;
use std::future::{ready, Ready};
use actix_service::Service;
use log::warn;
use rustls::pki_types::CertificateDer;
pub struct MtlsLogger;
impl actix_web::dev::Transform for MtlsLogger
where
S: actix_web::dev::Service, Error>,
S::Future: 'static,
{
type Response = ServiceResponse;
type Error = S::Error;
type InitError = ();
type Transform = MtlsLoggerMiddleware;
type Future = Ready>;
fn new_transform(&self, service: S) -> Self::Future {
ready(Ok(MtlsLoggerMiddleware { service }))
}
}
pub struct MtlsLoggerMiddleware {
service: S,
}
impl actix_web::dev::Service for MtlsLoggerMiddleware
where
S: actix_web::dev::Service, Error>,
S::Future: 'static,
{
type Response = ServiceResponse;
type Error = S::Error;
type Future = S::Future;
fn poll_ready(&mut self, cx: &mut std::task::Context<'_>) -> std::task::Poll> {
self.service.poll_ready(cx)
}
fn call(&mut self, mut req: ServiceRequest) -> Self::Future {
// Extract peer certs from the request's extensions (set by rustls via actix-web's TlsAcceptor)
// In practice, you may need to access the TLS info via the HttpConnector or a custom acceptor.
// For this example, we assume certs are placed into extensions by a higher-level integration.
let certs: Vec = req.extensions().get::>().cloned().unwrap_or_default();
// Log certificate metadata for auditability
for cert in &certs {
// Decode subject DN; in production use a proper X.509 parser like `x509-parser`
// This is a simplified representation:
warn!("mTLS client certificate presented ({} bytes)", cert.0.len());
}
// Store cert count for handlers if needed
req.extensions_mut().insert(certs);
self.service.call(req)
}
}
3. Log verification outcomes and anomalies
Ensure logs capture whether the client certificate passed validation, and include relevant failure reasons (e.g., unknown issuer, expired, revoked). Combine this with request identifiers to correlate logs across services.
- Log the TLS cipher suite and negotiated protocol version for each request.
- Record whether CRL/OCSP checks were performed and their results.
- Include the mapped identity (e.g., CN or SAN) in authorization logs to support traceability and detect BOLA/IDOR patterns.
By combining these code-level practices with continuous scanning using tools like middleBrick, you can detect whether mTLS endpoints produce sufficient logs and whether authentication outcomes are observable in audit trails.