Broken Authentication in Rocket with Firestore
Broken Authentication in Rocket with Firestore — how this specific combination creates or exposes the vulnerability
Broken Authentication occurs when identity management functions are implemented incorrectly, allowing attackers to compromise passwords, keys, or session tokens. In a Rocket application using Google Firestore as the backend datastore, the risk emerges from how authentication state is derived, stored, and validated rather than from Firestore itself being insecure.
Rocket does not provide a built-in authentication system; developers typically introduce guards, sessions, or JWTs and then rely on Firestore to store user credentials or session records. If passwords are stored without proper hashing, or if session identifiers are predictable and stored in client-side cookies without HttpOnly and Secure flags, the attack surface expands. Firestore security rules may inadvertently allow unauthenticated reads of user documents when rules are misconfigured, enabling enumeration of valid user identifiers.
Another common pattern in Rocket is using Firestore to store OAuth or SSO provider states. If these states are not validated strictly or are reused, authorization bypass can occur. Additionally, because Rocket is a web framework that compiles to a binary, developers might assume server-side logic is sufficient and neglect client-side protections, such as securing cookies with the SameSite attribute. Without rate limiting on authentication endpoints, credential stuffing and brute-force attacks become feasible, and Firestore usage metrics might not raise alarms because reads are inexpensive at small scales.
The combination of Rocket's type-safe handlers and Firestore's flexible document model can obscure improper authorization checks. For example, a handler might fetch a user document by ID derived from a path parameter without verifying that the requesting user owns that ID. This leads to BOLA/IDOR, which is often classified under broken authentication because it allows unauthorized access to account data. The scanner checks in middleBrick specifically test for unauthenticated access to user-like endpoints and cross-reference Firestore document patterns with runtime behavior to highlight these gaps.
Real-world attack patterns include stealing session cookies via XSS due to missing Secure and HttpOnly flags, or exploiting weak password reset tokens stored in Firestore without expiration. middleBrick’s authentication and BOLA/IDOR checks, run in parallel with other security tests, can surface these issues by probing unauthenticated endpoints and analyzing rule-based access alongside runtime responses.
Firestore-Specific Remediation in Rocket — concrete code fixes
Remediation focuses on secure credential storage, strict session management, and precise authorization checks. Below are concrete examples using the Firestore Rust SDK within a Rocket handler.
Secure password storage and verification
Never store plaintext passwords. Use argon2 via the password-hash crate to hash and verify passwords before writing to Firestore.
use rocket::serde::json::Json;
use rocket::State;
use google_cloud_firestore::client::Client;
use argon2::{Argon2, PasswordHash, PasswordHasher, PasswordVerifier};
use serde::{Deserialize, Serialize};
#[derive(Deserialize)]
struct LoginPayload {
email: String,
password: String,
}
#[post("/login", data = "&payload")]
async fn login(
payload: Json,
db: &State,
) -> Result<rocket::response::status::Accepted, rocket::response::status::Unauthorized> {
let doc_ref = db.collection("users").doc(&payload.email);
let snapshot = doc_ref.get().await.map_err(|_| rocket::http::Status::Unauthorized)?;
let user: UserRecord = snapshot.deserialize().map_err(|_| rocket::http::Status::Unauthorized)?;
let parsed = PasswordHash::new(&user.password_hash).map_err(|_| rocket::http::Status::Unauthorized)?;
if Argon2::default().verify_password(payload.password.as_bytes(), &parsed).is_ok() {
// Create a secure session token and store it separately; do not expose user hash
Ok(rocket::response::status::Accepted { /* session cookie set via headers */ })
} else {
Err(rocket::http::Status::Unauthorized)
}
}
#[derive(Serialize, Deserialize)]
struct UserRecord {
email: String,
password_hash: String,
#[serde(rename = "type")]
user_type: String,
}
Session cookies with secure attributes
When setting session cookies in Rocket, ensure HttpOnly, Secure, and SameSite attributes are configured. Use Rocket's CookieJar to manage this safely.
use rocket::http::Cookie;
use rocket::request::Request;
use rocket::response::Response;
fn secure_session_jar() -> CookieJar {
let mut jar = CookieJar::new();
jar.add_private(Cookie::build(("session_id", "random-uuid-here"))
.http_only(true)
.secure(true)
.same_site(rocket::http::SameSite::Strict)
.finish());
jar
}
Authorization with Firestore document ownership
Always validate ownership before reading or modifying a document. Use the authenticated user's ID from the request context rather than trusting path parameters alone.
use rocket::serde::json::Json;
use rocket::request::Request;
use google_cloud_firestore::client::Client;
async fn get_user_data(
user_id: String,
requester_id: String,
db: &State,
) -> Result<Json<UserDocument>, rocket::http::Status> {
if user_id != requester_id {
return Err(rocket::http::Status::Forbidden);
}
let doc_ref = db.collection("users").doc(&user_id);
let snapshot = doc_ref.get().await.map_err(|_| rocket::http::Status::InternalServerError)?;
let doc: UserDocument = snapshot.deserialize().map_err(|_| rocket::http::Status::InternalServerError)?;
Ok(Json(doc))
}
Rate limiting authentication endpoints
Apply basic rate limiting to login and password reset endpoints to mitigate brute-force attacks. This can be implemented via request guards that track attempts per IP or email in a short-lived cache (not shown here, as Firestore is not ideal for high-frequency counters; consider a dedicated cache layer).
middleBrick’s checks complement these fixes by validating that authentication endpoints require credentials and that Firestore rules do not permit public access to sensitive collections.
Related CWEs: authentication
| CWE ID | Name | Severity |
|---|---|---|
| CWE-287 | Improper Authentication | CRITICAL |
| CWE-306 | Missing Authentication for Critical Function | CRITICAL |
| CWE-307 | Brute Force | HIGH |
| CWE-308 | Single-Factor Authentication | MEDIUM |
| CWE-309 | Use of Password System for Primary Authentication | MEDIUM |
| CWE-347 | Improper Verification of Cryptographic Signature | HIGH |
| CWE-384 | Session Fixation | HIGH |
| CWE-521 | Weak Password Requirements | MEDIUM |
| CWE-613 | Insufficient Session Expiration | MEDIUM |
| CWE-640 | Weak Password Recovery | HIGH |