Side Channel Attack in Axum
How Side Channel Attack Manifests in Axum
Side channel attacks in Axum applications exploit timing differences, memory access patterns, and resource consumption to extract sensitive information. Unlike traditional attacks that target application logic directly, side channel attacks observe indirect effects of operations to infer secrets.
In Axum applications, timing attacks are particularly relevant when handling authentication and authorization. Consider an endpoint that validates user credentials:
async fn authenticate(&self, user: String, pass: String) -> Result<User, Error> {
let user_record = User::find_by_username(&user).await?;
if user_record.password_hash != hash_password(pass) {
return Err(Error::Unauthorized);
}
Ok(user_record)
}This implementation leaks information through timing. A non-existent username returns immediately, while an existing user with a wrong password triggers the hash comparison, taking longer. An attacker can measure response times to enumerate valid usernames.
Memory access patterns create another side channel. When handling different user roles, conditional logic based on user attributes can leak information:
async fn get_user_data(&self, user_id: String, requesting_user: UserId) -> Result<Json<UserData>, Error> {
let target_user = User::find_by_id(&user_id).await?;
let requesting_user = User::find_by_id(&requesting_user).await?;
if requesting_user.role == Role::Admin || requesting_user.id == target_user.id {
// Admin or self can access
return Ok(Json(target_user.data.clone()));
} else if requesting_user.role == Role::Premium {
// Premium users get limited data
return Ok(Json(target_user.data.clone().limit_to_premium()));
} else {
// Free users get minimal data
return Ok(Json(target_user.data.clone().limit_to_free()));
}
}The different code paths execute varying amounts of work, creating timing differences an attacker can measure. Even when the same HTTP status code is returned, the response time reveals whether the user exists and what role the requester has.
Resource exhaustion attacks also create side channels. An endpoint that performs expensive operations based on user input:
async fn process_large_data(&self, data: Vec<u8>) -> Result<Json<ResultData>, Error> {
let processed = heavy_computation(&data).await?;
Ok(Json(processed))
}Without proper limits, an attacker can send varying payload sizes to measure how long processing takes, potentially inferring implementation details or causing denial of service conditions.
Axum-Specific Detection
Detecting side channel vulnerabilities in Axum requires both manual code review and automated scanning. middleBrick's black-box scanning approach is particularly effective because it measures actual runtime behavior without requiring source code access.
For timing attacks, middleBrick measures response variations across multiple requests. When scanning an authentication endpoint, it submits both valid and invalid credentials while measuring response times:
$ middlebrick scan https://api.example.com/auth/login
Authentication Timing Analysis:
✓ No significant timing variations detected (max diff: 2ms)
✓ Constant-time comparison appears implementedThe scanner uses statistical analysis to determine if timing differences exceed normal network variance. For endpoints with authorization logic, it tests with different user roles and measures response time distributions.
middleBrick's LLM security checks are relevant for Axum applications using AI features. System prompt leakage can occur through timing when different prompts trigger different processing paths:
async fn process_prompt(&self, prompt: String) -> Result<Json<Response>, Error> {
let response = match classify_prompt(&prompt) {
PromptType::SimpleQuestion => handle_simple_question(prompt),
PromptType::CodeGeneration => handle_code_generation(prompt),
PromptType::ComplexAnalysis => handle_complex_analysis(prompt),
Ok(Json(response))
}middleBrick detects if different prompt types create measurable timing variations that could leak information about the classification logic.
For resource-based side channels, middleBrick tests with varying payload sizes and measures CPU utilization patterns. The scanner identifies endpoints where processing time correlates with input characteristics:
$ middlebrick scan https://api.example.com/process
Resource Analysis:
⚠️ Input-dependent processing detected (variance: 450ms)
⚠️ No rate limiting on endpoint
⚠️ Potential for resource exhaustion attacksThe CLI tool provides JSON output for integration with CI/CD pipelines:
$ middlebrick scan --format=json https://api.example.com/auth
{
"side_channel": {
"timing_vulnerability": false,
"resource_exhaustion": true,
"recommendations": ["Implement constant-time comparisons", "Add rate limiting"]
}
}Axum-Specific Remediation
Remediating side channel vulnerabilities in Axum requires architectural changes and careful implementation of security best practices. For timing attacks, use constant-time comparison functions:
use subtle::ConstantTimeEq;
async fn authenticate(&self, user: String, pass: String) -> Result<User, Error> {
let valid_password = user_record.password_hash.ct_eq(&hash_password(pass)).unwrap_u8() == 1;
if valid_password {
Ok(user_record)
} else {
Err(Error::Unauthorized)
}
}This implementation ensures the comparison takes constant time regardless of whether the user exists or the password is correct. The unwrap_or_default() ensures the same code path executes for both valid and invalid usernames.
For authorization logic, eliminate conditional branches that create timing variations:
async fn get_user_data(&self, user_id: String, requesting_user: UserId) -> Result<Json<UserData>, Error> {
let target_user = User::find_by_id(&user_id).await?;
let requesting_user = User::find_by_id(&requesting_user).await?;
let can_access = requesting_user.role == Role::Admin || requesting_user.id == target_user.id;
let data_to_return = if can_access {
target_user.data.clone()
} else {
UserData::default() // Empty data structure
};
// Always perform same operations regardless of access
let processed = process_data(data_to_return).await;
Ok(Json(processed))
}This pattern ensures the same operations execute regardless of authorization outcome, eliminating timing differences.
Implement rate limiting at the Axum layer to prevent resource exhaustion attacks:
use tower_http::rate_limit::RateLimitLayer;
use axum::routing::get;
let app = Router::new()
.route("/auth/login", post(login_handler))
.route("/data/process", post(process_handler))
.layer(RateLimitLayer::new(100)); // 100 requests per windowThe RateLimitLayer middleware provides configurable rate limiting that prevents attackers from making enough requests to measure timing variations effectively.
For LLM endpoints, implement constant-time prompt processing:
async fn process_prompt(&self, prompt: String) -> Result<Json<Response>, Error> {
// Always perform same amount of work
let classified = classify_prompt(&prompt).await;
let response = match classified {
PromptType::SimpleQuestion => handle_simple_question(prompt),
PromptType::CodeGeneration => handle_code_generation(prompt),
PromptType::ComplexAnalysis => handle_complex_analysis(prompt),
};
// Add constant delay to mask processing time differences
let delay = tokio::time::sleep(std::time::Duration::from_millis(100)).await;
Ok(Json(response))
}This approach adds a fixed delay to mask any processing time differences, ensuring consistent response times regardless of prompt complexity.
Frequently Asked Questions
How can I test my Axum application for side channel vulnerabilities?
middlebrick scan https://yourapi.com. The scanner measures response time variations and resource usage patterns across multiple requests. For timing attacks, it tests with different inputs and analyzes statistical variance. You can integrate this into your CI/CD pipeline using the GitHub Action to automatically scan staging APIs before deployment.Does Axum provide built-in protection against side channel attacks?
subtle, eliminate conditional timing variations in your handlers, and add rate limiting. middleBrick's scanning can identify these vulnerabilities even in production environments without requiring code changes.