Sql Injection in Actix with Mutual Tls
Sql Injection in Actix with Mutual Tls — how this specific combination creates or exposes the vulnerability
SQL injection in Actix web applications occurs when untrusted input is concatenated into SQL queries without proper validation or parameterization. Mutual TLS (mTLS) adds client certificate verification to the TLS handshake, which authenticates the connecting client but does not affect how the server builds SQL statements. As a result, mTLS does not prevent SQL injection; it only ensures that the request comes from a trusted client. Attackers can still exploit injection flaws in query construction even when mTLS is enforced, and the presence of mTLS may create a false sense of security, leading developers to overlook input validation and parameterized queries.
In an Actix web service using mTLS, the server authenticates clients via client certificates, but SQL injection risk remains if database queries use string interpolation or concatenation. For example, extracting identity information from the client certificate (e.g., common name) and directly embedding it into SQL without sanitization introduces injection surfaces. Consider a handler that uses the client certificate subject to build a query:
use actix_web::{web, App, HttpServer, Responder};
use openssl::ssl::{SslAcceptor, SslFiletype, SslMethod};
async fn get_user_by_cert_identity(query: web::Query>) -> impl Responder {
let client_name = query.get("name").unwrap_or(&"unknown".to_string());
let sql = format!("SELECT * FROM users WHERE name = '{}'", client_name);
// execute sql ...
format!("Query: {}", sql)
}
fn main() -> std::io::Result<()> {
let mut builder = SslAcceptor::mozilla_intermediate(SslMethod::tls()).unwrap();
builder.set_private_key_file("key.pem", SslFiletype::PEM)?;
builder.set_certificate_chain_file("cert.pem")?;
builder.set_client_ca_file("ca.pem")?;
builder.set_verify(openssl::ssl::SslVerifyMode::PEER | openssl::ssl::SslVerifyMode::FAIL_IF_NO_PEER_CERT, None);
HttpServer::new(move || {
App::new()
.wrap(actix_web_openssl::OpenSsl::new(builder.clone()))
.route("/user", web::get().to(get_user_by_cert_identity))
})
.bind_openssl("127.0.0.1:8443", builder)?
.run()
.await
}
In this example, client_name is taken from query parameters (or could be derived from certificate fields) and directly interpolated into SQL. An attacker who controls the input (or a compromised client) can supply values such as ' OR '1'='1, leading to unauthorized data access. Even with mTLS ensuring the client possesses a valid certificate, the application must treat all inputs as untrusted. The mTLS layer authenticates but does not sanitize or parameterize queries, so the injection flaw persists.
middleBrick scans can detect such injection patterns by analyzing the unauthenticated attack surface and, when an OpenAPI spec is available, cross-referencing endpoint definitions with runtime behavior. Findings will highlight the lack of parameterized queries and provide remediation guidance aligned with OWASP API Top 10 and related frameworks, noting that mTLS alone is insufficient to mitigate SQL injection.
Mutual Tls-Specific Remediation in Actix — concrete code fixes
To remediate SQL injection in Actix while using mTLS, focus on query construction and input handling, not the TLS layer. Always use parameterized queries or prepared statements, and treat any data derived from the request—including certificate attributes—as untrusted. Below are concrete code examples demonstrating safe practices with mTLS in Actix.
1. Use parameterized queries with a database library that supports them (e.g., sqlx):
use actix_web::{web, App, HttpServer, Responder};
use openssl::ssl::{SslAcceptor, SslFiletype, SslMethod};
use sqlx::postgres::PgPoolOptions;
use std::sync::Arc;
struct AppState {
pool: Arc,
}
async fn get_user_safe(
web::Query(params): web::Query>,
data: web::Data,
) -> impl Responder {
let client_name = params.get("name").map(|s| s.as_str()).unwrap_or("unknown");
// Parameterized query prevents SQL injection
let user = sqlx::query("SELECT * FROM users WHERE name = $1")
.bind(client_name)
.fetch_optional(&*data.pool)
.await
.unwrap_or_default();
format!("User: {:?}", user)
}
fn create_ssl_acceptor() -> SslAcceptor {
let mut builder = SslAcceptor::mozilla_intermediate(SslMethod::tls()).unwrap();
builder.set_private_key_file("key.pem", SslFiletype::PEM).unwrap();
builder.set_certificate_chain_file("cert.pem").unwrap();
builder.set_client_ca_file("ca.pem").unwrap();
builder.set_verify(
openssl::ssl::SslVerifyMode::PEER | openssl::ssl::SslVerifyMode::FAIL_IF_NO_PEER_CERT,
None,
);
builder.build()
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
let pool = Arc::new(PgPoolOptions::new().connect("postgres://user:pass@localhost/db").await.unwrap());
let ssl_builder = create_ssl_acceptor();
HttpServer::new(move || {
App::new()
.app_data(web::Data::new(AppState { pool: Arc::clone(&pool) }))
.wrap(actix_web_openssl::OpenSsl::new(ssl_builder.clone()))
.route("/user", web::get().to(get_user_safe))
})
.bind_openssl("127.0.0.1:8443", ssl_builder)?
.run()
.await
}
2. Validate and sanitize certificate-derived data: If you use fields from the client certificate, validate them against an allowlist or strict pattern before using them in queries.
use regex::Regex;
fn validate_common_name(cn: &str) -> bool {
let re = Regex::new(r"^[a-zA-Z0-9_-]{1,64}$").unwrap();
re.is_match(cn)
}
async fn get_user_with_cert_validation(
cert: Option>,
) -> impl Responder {
if let Some(cert) = cert {
let cn = cert.subject_name().entries_by_nid(openssl::nid::Nid::COMMONNAME)
.next()
.and_then(|e| e.data().as_utf8().ok())
.map(|s| s.to_string());
if let Some(name) = cn {
if validate_common_name(&name) {
// safe to use name in a parameterized query
}
}
}
"Invalid or missing certificate identity".to_string()
}
These approaches ensure that even with mTLS enforcing client authentication, SQL injection risks are mitigated through parameterized queries and strict input validation. middleBrick can verify that your endpoints use safe patterns and report any remaining injection risks alongside mTLS configuration details.
Related CWEs: inputValidation
| CWE ID | Name | Severity |
|---|---|---|
| CWE-20 | Improper Input Validation | HIGH |
| CWE-22 | Path Traversal | HIGH |
| CWE-74 | Injection | CRITICAL |
| CWE-77 | Command Injection | CRITICAL |
| CWE-78 | OS Command Injection | CRITICAL |
| CWE-79 | Cross-site Scripting (XSS) | HIGH |
| CWE-89 | SQL Injection | CRITICAL |
| CWE-90 | LDAP Injection | HIGH |
| CWE-91 | XML Injection | HIGH |
| CWE-94 | Code Injection | CRITICAL |