Sql Injection in Axum with Api Keys
Sql Injection in Axum with Api Keys — how this specific combination creates or exposes the vulnerability
SQL injection in an Axum application becomes significantly more likely when API keys are handled incorrectly. Axum is a web framework for Rust, and while it does not include built-in SQL abstractions, developers commonly integrate databases via libraries such as SQLx or Diesel. API keys are often used for authentication and authorization, typically passed as HTTP headers. If an API key influences which database query is constructed without strict input validation or safe query patterns, it can become an indirect vector for SQL injection.
Consider a scenario where an API key is used to look up tenant or user data, and that key is concatenated into a SQL string. For example, extracting the key from headers and using it in a raw query exposes the endpoint to injection if the key is not strictly validated. An attacker could supply a crafted key such as ' OR '1'='1 that alters query logic, potentially bypassing intended filters or escalating access across tenants. Even when the key is expected to be an opaque token, poor error handling or logging may inadvertently expose database behavior that aids further exploitation.
Another common pattern involves using the API key to determine access scope, such as selecting a subset of rows via an id = {key} pattern. If the key is numeric but not bounded or type-checked, an attacker might leverage SQL comments or multi-statement payloads to interfere with query structure. Because Axum routes are often organized around middleware and extractors, developers may inadvertently pass extracted key values into dynamic SQL without sanitization, especially when building reporting or administrative endpoints. The risk is compounded when applications log full queries or keys, as this can reveal schema details useful for targeted attacks.
The combination of Axum's flexible extractor model and the prevalence of SQL-based backends means that API keys must be treated as untrusted input. Even if the key itself is not directly concatenated into SQL, downstream services or configuration derived from the key might be. For instance, a key could map to a data partition that influences table or column names in dynamic queries. Without parameterized queries or strict allowlists, such patterns remain vulnerable to injection techniques like second-order injection or time-based blind injection.
Real-world attack patterns mapped to OWASP API Top 10 and the broader OWASP Top 10 for APIs include excessive data exposure via error messages, broken object level authorization when keys influence row-level queries, and injection due to concatenated strings. These issues are detectable by scanning tools that correlate authentication mechanisms with database interaction patterns. Using parameterized queries, strict validation of key formats, and avoiding dynamic SQL construction based on key values are essential mitigations. Continuous scanning and runtime analysis help identify these issues before attackers can exploit them.
Api Keys-Specific Remediation in Axum — concrete code fixes
Remediation focuses on ensuring API keys never directly influence SQL text. In Axum, extractors should validate and transform keys into safe identifiers or parameters before any database interaction. Below are concrete, working examples demonstrating secure patterns using SQLx with PostgreSQL.
First, define a typed extractor that validates the API key format and maps it to a known identifier without string concatenation:
use axum::extract::Request;
use axum::http::HeaderValue;
use std::convert::Infallible;
use regex::Regex;
async fn validate_api_key(
request: Request,
) -> Result<(String, Request), (axum::http::StatusCode, String)> {
let headers = request.headers();
let key = headers.get("X-API-Key")
.and_then(|v| v.to_str().ok())
.ok_or((axum::http::StatusCode::UNAUTHORIZED, "Missing API key".to_string()))?;
// Strict allowlist: only alphanumeric and underscore, 8–64 chars
let re = Regex::new(r"^[A-Za-z0-9_]{8,64}$").unwrap();
if !re.is_match(key) {
return Err((axum::http::StatusCode::UNAUTHORIZED, "Invalid API key".to_string()));
}
// At this point, key is safe to use as an identifier in parameterized context
Ok((key.to_string(), request))
}
Next, use the validated key as a parameter in SQLx queries rather than interpolating it into the SQL string:
use sqlx::postgres::PgPool;
use sqlx::Row;
async fn get_tenant_data(pool: &PgPool, api_key: &str) -> Result {
// Safe: api_key is passed as a parameter, not concatenated
let row = sqlx::query("SELECT tenant_name FROM tenants WHERE api_key = $1")
.bind(api_key)
.fetch_one(pool)
.await?;
let name: String = row.try_get(0)?;
Ok(name)
}
For scenarios where the API key determines access scope, avoid dynamic table or column names derived from the key. Instead, use allowlisted mappings:
async fn get_user_data(
pool: &PgPool,
api_key: &str,
user_id: i32,
) -> Result<(i32, String), sqlx::Error> {
// Map key to a tenant ID using a preloaded lookup table
let tenant_id: i32 = sqlx::query_scalar("SELECT tenant_id FROM api_key_mapping WHERE api_key = $1")
.bind(api_key)
.fetch_one(pool)
.await?;
// Use tenant_id as a parameter, not as part of SQL text
let (user_id, user_name): (i32, String) = sqlx::query_as("SELECT id, name FROM users WHERE tenant_id = $1 AND id = $2")
.bind(tenant_id)
.bind(user_id)
.fetch_one(pool)
.await?;
Ok((user_id, user_name))
}
These patterns ensure that API keys are never interpolated into SQL strings, preventing injection. They also align with middleware design in Axum, where extractors can centralize validation and keep route handlers focused on business logic. Continuous scanning and runtime analysis remain important to detect any regressions or overlooked dynamic query construction.
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 |