Poodle Attack in Actix with Mutual Tls
Poodle Attack in Actix with Mutual Tls — how this specific combination creates or exposes the vulnerability
The Poodle (Padding Oracle On Downgraded Legacy Encryption) attack targets weaknesses in SSL 3.0 and the use of CBC-mode ciphers with predictable initialization vectors. When a server supports SSL 3.0 and negotiates TLS using CBC ciphers, an attacker can perform chosen-ciphertext decryption of secure cookies by observing whether padding errors differ in timing or error messages. In Actix web applications that enable Mutual TLS (mTLS), the risk arises not from the application logic itself, but from the TLS configuration exposed by the server stack. If the Actix server (for example, via Rustls or OpenSSL bindings) negotiates SSL 3.0 or CBC-based cipher suites and also requests client certificates, an attacker who can position themselves as a man-in-the-middle can use the mTLS handshake to learn whether padding is valid while downgrading or manipulating the negotiated protocol. This combination makes the server an oracle: the client certificate requirement ensures the attacker can relay authentication attempts, while the weak cipher suite allows decryption of session cookies or other sensitive data transported under TLS.
Even with client certificates required, if the cipher suite list includes CBC modes and SSL 3.0 is reachable, the attack surface remains. For example, an attacker who can terminate an mTLS connection on their own infrastructure and relay it to the Actix backend can submit crafted ciphertexts and observe responses to decrypt secure tokens. The presence of Mutual TLS does not prevent Poodle; it changes the attacker’s position from an unauthenticated client to a client that must present a valid certificate to reach the oracle. If the server’s TLS configuration prefers weak ciphers for compatibility, the mTLS handshake will still negotiate CBC-based suites, enabling the padding oracle to function. Therefore, the specific combination of Poodle and mTLS in Actix is dangerous when the server supports legacy protocols and does not enforce strong cipher preferences, regardless of whether client certificates are used.
Mutual Tls-Specific Remediation in Actix — concrete code fixes
To mitigate Poodle in an Actix service with Mutual TLS, you must disable SSL 3.0, remove CBC cipher suites, and enforce modern, AEAD-based ciphers. Below are concrete, working examples using Rustls and native-tls (or openssl) in Actix-web. These snippets show how to configure the server to require client certificates while ensuring only secure protocols and ciphers are negotiated.
Remediation with Rustls (recommended)
Rustls does not support SSL 3.0 or CBC by default in secure configurations, but you should explicitly set cipher suites and versions to avoid accidental weak negotiation. Use rustls::ServerConfig with client authentication and a modern cipher list.
use actix_web::{web, App, HttpServer};
use rustls::{Certificate, PrivateKey, ServerConfig, protocols::ProtocolVersion};
use rustls::pki_types::{CertificateDer, PrivateKeyDer, UnixTime};r/>use std::sync::Arc;
async fn run_secure_mtls_rustls() -> std::io::Result<()> {
// Load server certificate and key
let cert_chain = vec![CertificateDer::from(include_bytes("../certs/server.crt").to_vec())];
let priv_key = PrivateKeyDer::Pkcs8(include_bytes("../certs/server.key").to_vec().into());
let cert_resolver = move |_sni: rustls::pki_types::ServerName| -> Option<Vec<CertificateDer>> {
Some(cert_chain.clone())
};
// Configure mTLS: require and validate client certificates
let mut server_config = ServerConfig::builder()
.with_safe_defaults()
.with_no_client_auth()
.with_client_cert_verifier(Arc::new(|_end_entity, _intermediates| {
// Implement custom validation as needed (e.g., verify cert against a trust store)
Ok(()
}));
// Explicitly set secure protocols and cipher suites (TLS 1.2+ with AEAD only)
server_config.versions = vec![ProtocolVersion::TLSv1_2, ProtocolVersion::TLSv1_3];
// rustls with safe_defaults already excludes SSL3 and CBC; optionally tighten further:
server_config.alpn_protocols = vec![b"h2".to_vec(), b"http/1.1".to_vec()];
let acceptor = TlsAcceptor::from(Arc::new(server_config));
HttpServer::new(move || {
App::new().route("/", web::get().to(|| async { "secure" }))
})
.bind_rustls("127.0.0.1:8443", acceptor)?
.run()
.await
}
Remediation with native-tls or openssl-based Actix (if required)
If you rely on native-tls or an OpenSSL-based acceptor, explicitly disable SSL 3.0 and restrict ciphers to modern suites. The following example uses native-tls with Actix-web to require client certs while disabling weak protocols.
use actix_web::{web, App, HttpServer};
use native_tls::{TlsAcceptor, Identity};
use std::fs::File;
use std::io::BufReader;
use std::sync::Arc;
async fn run_secure_mtls_native() -> std::io::Result<()> {
// Identity (server cert + key)
let cert_file = "../certs/server.p12";
let mut identity_file = BufReader::new(File::open(cert_file)?);
let identity = Identity::from_pkcs12(&mut identity_file, "password")?;
// Configure TLS acceptor with mTLS and secure settings
let mut builder = native_tls::TlsAcceptor::builder(identity);
// Require client authentication
builder.client_auth(native_tls::ClientAuthMode::Require);
// Disable SSLv3 and TLSv1.0/1.1; native-tls typically defaults to TLS1.2+
builder.min_protocol_version(Some(native_tls::Protocol::Tlsv1_2));
// Optionally set cipher list to exclude CBC
builder.ciphers("TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256")?;
let acceptor = builder.build()?;
let tls_acceptor = Arc::new(acceptor);
HttpServer::new(move || {
App::new().route("/", web::get().to(|| async { "secure" }))
})
.bind_rustls("127.0.0.1:8443", tls_acceptor)?
.run()
.await
}
Key remediation steps summarized:
- Disable SSL 3.0 and TLS 1.0/1.1; enforce TLS 1.2 or 1.3.
- Remove CBC-based cipher suites; prefer AES-GCM and ChaCha20-Poly1305.
- Keep client certificate validation; ensure the trust store is tightly scoped.
- Test the configuration with tools that detect protocol/cipher downgrade attempts.