Poodle Attack in Axum with Api Keys
Poodle Attack in Axum with Api Keys — how this specific combination creates or exposes the vulnerability
The Poodle attack (CVE-2014-3566) exploits weaknesses in SSL 3.0, particularly the use of predictable initialization vectors in CBC-mode ciphersuites. In Axum applications that terminate TLS with a server certificate and rely on API keys for client authorization, this combination can expose sensitive material when an endpoint is reachable over SSL 3.0. Even if the server certificate is strong, an attacker who can position a client on a network that allows SSL 3.0 negotiation may perform padding oracle attacks to gradually recover plaintext from encrypted request bodies or cookies. API keys often travel in headers or cookies; if those transports fall back to SSL 3.0, the keys can be revealed through repeated oracle interactions.
In Axum, handlers commonly read API keys from headers (e.g., Authorization: Bearer <key> or a custom x-api-key header). When SSL 3.0 is enabled on the TLS acceptor, an unauthenticated attacker can intercept or downgrade the protocol version during the handshake. Because the attack is unauthenticated, it does not require valid API keys; it only requires the endpoint to support SSL 3.0. MiddleBrick’s unauthenticated scan checks for SSL 3.0 support and flags findings under Data Exposure and Encryption checks, highlighting the risk that API keys could be extracted via a Poodle-style oracle.
Additionally, if Axum services are behind a load balancer or reverse proxy that historically negotiated SSL 3.0 for legacy clients, the effective transport between the proxy and the service might still carry implications for session handling and key exposure. The scanner’s SSL/TLS checks correlate protocol support with the presence of authorization headers and cookies in indexed endpoints, increasing the severity of findings when API keys are transmitted over potentially downgraded channels. The combination of a deprecated protocol and bearer credentials creates a scenario where confidentiality of keys is compromised even when the application logic itself is sound.
Api Keys-Specific Remediation in Axum — concrete code fixes
Remediation focuses on disabling SSL 3.0 and ensuring API keys are never transmitted over weak ciphers or protocols. In Axum, this is typically enforced at the TLS acceptor or proxy layer, not within application handlers. Below are concrete configuration examples for a typical Rust/Tower/HTTPS setup using rustls, alongside Axum routes that expect API keys.
First, configure the server to use modern protocols and ciphersuites, explicitly excluding SSL 3.0. Using rustls, you can define a ServerConfig that disables legacy protocols:
use rustls::{ServerConfig, ProtocolVersion, CipherSuite};
use std::sync::Arc;
let mut config = ServerConfig::builder()
.with_safe_defaults()
.with_no_client_auth()
.with_single_cert(vec![cert_der], private_key_der)
.expect("invalid certificate or key");
// Explicitly set protocol versions to TLSv1.2 and TLSv1.3 only
config.versions = vec![ProtocolVersion::TLSv1_2, ProtocolVersion::TLSv1_3];
// Ensure weak ciphers (including those vulnerable to padding oracle) are not included
config.ciphersuites = vec![
CipherSuite::TLS13_AES_256_GCM_SHA384,
CipherSuite::TLS13_CHACHA20_POLY1305_SHA256,
CipherSuite::TLS_AES_128_GCM_SHA256,
];
let acceptor = TlsAcceptor::from(Arc::new(config));
In practice, many Axum services use axum::Server::bind with a TLS acceptor. Ensure the acceptor is built with the above constraints. If you terminate TLS at a load balancer, disable SSL 3.0 there and enforce modern ciphers. Also, avoid sending API keys in URLs or logs; prefer headers and mark them as sensitive.
Example Axum handler that expects an API key in a header (safe when transport is hardened):
use axum::{routing::get, Router, extract::State, http::HeaderMap};
use std::net::SocketAddr;
struct ApiKeyValidator(String);
async fn validate_key(
State(validator): State,
headers: HeaderMap,
) -> &'static str {
const EXPECTED: &str = "x-api-key";
match headers.get(EXPECTED) {
Some(value) if value == validator.0 => "OK",
_ => "Forbidden",
}
}
#[tokio::main]
async fn main() {
let validator = ApiKeyValidator("super-secret-key".to_string());
let app = Router::new()
.route("/data", get(validate_key))
.with_state(validator);
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
// Configure TLS acceptor externally and bind with .tls_config(...)
axum::Server::bind(&addr)
.serve(app.into_make_service())
.await
.unwrap();
}