Cross Site Request Forgery in Actix with Mongodb
Cross Site Request Forgery in Actix with Mongodb — how this specific combination creates or exposes the vulnerability
Cross Site Request Forgery (CSRF) in an Actix web service that uses MongoDB as the backend datastore can arise when state-changing endpoints rely solely on cookies for session identity without anti-CSRF protections. In this combination, an attacker can trick a logged-in user’s browser into issuing authenticated requests to Actix routes that mutate data in MongoDB, because cookies are sent automatically with same-origin and cross-origin requests. If the Actix handler performs unsafe method parsing (e.g., parsing JSON from the request body but also accepting query parameters for critical operations) and does not validate the origin or include a per-request token, the attacker can forge requests that directly modify MongoDB documents on behalf of the victim.
Consider an Actix route that updates a user’s profile and writes to MongoDB using a client-supplied user identifier. If the route trusts an unsigned cookie for identity and does not verify a CSRF token, an attacker can host a malicious page that sends a crafted POST to that endpoint. Because the request arrives with valid session cookies, Actix may authorize it and then build a MongoDB update using an unsanitized or attacker-controlled identifier, leading to unintended updates. This is especially risky when the endpoint does not perform proper Content-Type enforcement and does not reject requests that lack appropriate headers (e.g., relying only on same-origin policy). The MongoDB driver usage in Actix does not inherently protect against CSRF; it merely executes the commands your application sends, so the framework must enforce strict origin checks and token validation before constructing and executing database operations.
An example of a vulnerable Actix handler that combines MongoDB updates with CSRF risk might accept query parameters for identifying which document to update. If the handler builds a MongoDB filter from raw query parameters without verifying the requester’s intent, an attacker can trick the user into visiting a URL like https://api.example.com/update-profile?userId=attackerId. When the browser sends this request with the user’s session cookie, Actix processes it and updates the corresponding MongoDB document as if the user intended the action. Because the handler did not validate the request origin or require a synchronizer token (e.g., a double-submit cookie or a custom header), the operation executes despite being forged. This pattern highlights the importance of treating cookies as not sufficient for state-changing operations and enforcing additional CSRF mitigation when working with stateful backends like MongoDB.
Mongodb-Specific Remediation in Actix — concrete code fixes
To mitigate CSRF in Actix when using MongoDB, enforce anti-CSRF tokens on all state-changing routes and avoid relying on cookies alone for authorization of sensitive operations. For routes that mutate data, require a custom header (such as X-Requested-With) or a per-request token, and validate the Origin or Referer header where appropriate. Combine this with strict input validation and the principle of least privilege for the MongoDB user your Actix service connects with.
Example: CSRF-safe Actix handler with MongoDB
The following example demonstrates a safer approach in Actix using the official MongoDB driver for Rust. It checks for a custom header and validates the origin before building and executing a MongoDB update. The handler uses a verified user identifier from session or JWT claims rather than trusting query parameters, and it uses typed MongoDB updates to avoid injection.
use actix_web::{web, HttpRequest, HttpResponse, Result};
use mongodb::{bson::{doc, oid::ObjectId}, Client};
async fn update_profile(
req: HttpRequest,
client: web::Data,
payload: web::Json,
) -> Result<HttpResponse> {
// Prefer an authenticated user identifier from JWT/session, not a query param.
let user_id = match req.extensions().get::() {
Some(id) => id,
None => return Ok(HttpResponse::Unauthorized().finish()),
};
// CSRF mitigation: require a custom header for state-changing requests.
const REQUIRED_HEADER: &str = "x-requested-with";
if req.headers().get(REQUIRED_HEADER).and_then(|v| v.to_str().ok()) != Some("XMLHttpRequest") {
return Ok(HttpResponse::Forbidden().body("Missing CSRF protection header"));
}
// Optional: validate Origin/Referer for additional defense-in-depth.
if let Some(origin) = req.headers().get("Origin") {
if origin != "https://trusted.example.com" {
return Ok(HttpResponse::Forbidden().body("Invalid origin"));
}
}
let database = client.database("appdb");
let collection = database.collection("users");
// Use a verified user ID; do not accept mutable identifiers from the request.
let filter = doc! { "_id": ObjectId::parse_str(&user_id).unwrap_or_else(|_| { return HttpResponse::BadRequest().finish(); }) };
let update = doc! {
"$set": {
"email": payload.email.clone(),
"displayName": payload.display_name.clone(),
}
};
match collection.update_one(filter, update, None).await {
Ok(result) if result.modified_count > 0 =
Ok(HttpResponse::Ok().json(serde_json::json!({ "status": "updated" }))),
Ok(_) =
Ok(HttpResponse::Ok().json(serde_json::json!({ "status": "no changes" }))),
Err(e) =
Ok(HttpResponse::InternalServerError().body(format!("Database error: {}", e))),
}
}
In this example, the handler does not derive the user identifier from query parameters or a mutable body field, which prevents an attacker from changing the target of the update. The MongoDB update uses a filter built from a verified identifier and a typed update document, avoiding injection risks. Requiring a custom header and optionally checking the Origin adds defense-in-depth against CSRF, even if the attacker can cause the user’s browser to load a crafted URL. For broader protection across the Actix application, integrate a CSRF token library or double-submit cookie pattern and ensure all non-GET routes validate the token before executing any MongoDB operations.