Dictionary Attack in Axum with Firestore
Dictionary Attack in Axum with Firestore — how this specific combination creates or exposes the vulnerability
A dictionary attack against an Axum API backed by Firestore typically targets authentication or account recovery endpoints where a user identifier (such as email) is supplied as input. Because Axum is a Rust web framework, developers often implement handlers that directly query Firestore based on the provided identifier. If the application does not enforce rate limits or consistent timing behavior, an attacker can iterate through a list of known usernames or emails and observe differences in response behavior to infer valid accounts.
Firestore does not inherently reveal whether a document exists at the path the caller provided; however, the way Axum processes the Firestore read determines information leakage. For example, if the handler performs a get on a document using the supplied identifier and then branches logic based on whether data is returned, the resulting HTTP status codes or response content can differ for existing versus non-existing documents. This discrepancy enables a remote attacker to build a valid set of credentials or emails without ever interacting with the legitimate backend owner.
The combination of Axum’s routing and Firestore’s document model also interacts poorly with common security checks. Authentication checks that rely on Firestore reads to confirm credentials may inadvertently provide timing channels. Additionally, if the API exposes user enumeration through user profile endpoints or password reset flows, and those endpoints are not instrumented with shared-rate limiting across the service, the attack surface expands. An attacker can run a distributed dictionary attack by rotating IPs or leveraging botnets, while Axum services continue to perform per-request Firestore operations that increase load and potentially expose logs or metrics that aid further reconnaissance.
OpenAPI specifications for such Axum services often describe query parameters for login or account lookup without conveying the risk of user enumeration. During an unauthenticated scan, middleBrick runs checks for Authentication, Input Validation, and Rate Limiting in parallel. It can detect whether responses for existing and non-existing users differ in timing or status, flagging the endpoint as a potential vector for credential guessing. Findings from such scans map to OWASP API Top 10 A07:2021 (Identification and Authentication Failures) and common insecure implementations where Firestore security rules are not aligned with least-privilege access, allowing broader read paths than intended.
To illustrate, consider an Axum handler that retrieves a user document by email and returns 200 if the document exists and a generic 401 otherwise. Without consistent timing and without protective controls like rate limiting, this handler effectively confirms the presence of the email in Firestore. middleBrick’s LLM/AI Security checks are particularly valuable here because they probe for user enumeration patterns and injection attempts that could amplify dictionary attack efficiency, ensuring that even indirect information leaks are surfaced.
Firestore-Specific Remediation in Axum
Remediation focuses on removing user enumeration, standardizing response behavior, and adding robust rate control. In Axum, you should design endpoints so that the existence of a user does not affect HTTP status codes or response timing. Use a constant-time flow that always performs a read, applies a cryptographic hash-based comparison for secrets, and returns a generic success acknowledgment for actions like password reset initiation.
First, ensure your Firestore security rules enforce strict access patterns and avoid broad read permissions that could aid an attacker during enumeration. Within Axum, structure handlers to always access the document path using a stable key and avoid branching on document presence. Below is a concrete Firestore code example for Axum using the Firestore Rust SDK, demonstrating a safe password reset initiation flow that avoids leaking whether an email exists.
use axum::{routing::post, Router};
use firestore::{FirestoreDb, FirestoreError};
use serde::{Deserialize, Serialize};
use std::sync::Arc;
#[derive(Deserialize)]
struct ResetRequest {
email: String,
}
#[derive(Serialize)]
struct ApiResponse {
message: String,
}
async fn handle_reset(
db: Arc<FirestoreDb>,
req: axum::Json<ResetRequest>
) -> Result<axum::Json<ApiResponse>, (axum::http::StatusCode, String)> {
// Always perform the read; do not early-return on missing document.
let doc_path = format!("users/{}", req.email);
let result: Result<Option<serde_json::Value>, FirestoreError> = db.get(&doc_path).await;
// Regardless of whether the document exists, proceed with the same logic.
// In a real implementation, you would queue an asynchronous job for reset
// and return a generic 202 to avoid timing differences.
let _ = result.map_err(|e| (axum::http::StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
Ok(axum::Json(ApiResponse {
message: "If the email is registered, a reset link has been sent.".to_string(),
}))
}
fn app() -> Router {
// Assume db is initialized elsewhere and wrapped in Arc
Router::new().route("/auth/password-reset", post(handle_reset))
}
This pattern ensures that the response time and status remain consistent, mitigating timing-based dictionary attacks. Combine this with per-endpoint rate limiting at the network or middleware layer to prevent rapid probing. middleBrick’s scan flow can validate that your handlers do not exhibit status or timing variance across existing and non-existing users, and the dashboard helps you track these changes over time.
For broader protection, integrate rate limiting before requests reach Axum handlers, and consider using token buckets or sliding windows that are shared across service instances. The Pro plan’s continuous monitoring can alert you when response characteristics drift, and the GitHub Action can gate merges if new endpoints introduce enumeration risks. Even when using Firestore emulators during development, ensure that the same security rules and constant-time logic are enforced to prevent accidental leakage in staging environments.
Finally, review your OpenAPI spec with middleBrick to confirm that authentication and account-related paths do not describe behavior that implies user enumeration. The scanner’s runtime checks will highlight discrepancies between declared parameters and actual response behavior, helping you align implementation with secure design principles.