Sql Injection Blind in Actix
How Sql Injection Blind Manifests in Actix
Blind SQL injection in Actix applications occurs when user input is unsafely incorporated into SQL queries, but the application does not return query results directly in responses. Instead, attackers infer information through boolean-based or time-based side channels. In Actix web frameworks, this commonly appears in handler functions that extract parameters from Path, Query, or Form extracts and concatenate them into SQL strings without parameterization.
Consider an Actix endpoint retrieving user profiles by ID:
use actix_web::{get, web, HttpResponse, Responder};
use sqlx::PgPool;
#[get("/profile/{id}")]
async fn get_profile(pool: web::Data, id: web::Path) -> impl Responder {
let query = format!("SELECT * FROM users WHERE id = '{}'", id.into_inner());
match sqlx::query(&query).fetch_one(pool.get_ref()).await {
Ok(user) => HttpResponse::Ok().json(user),
Err(_) => HttpResponse::NotFound().finish(),
}
}
Here, the id path parameter is directly interpolated into the SQL string. An attacker can exploit this via boolean-based blind SQLi by injecting payloads like ' AND 1=1-- (returns user) vs ' AND 1=2-- (returns 404), observing response differences to infer database structure. Time-based variants use payloads like ' OR (SELECT pg_sleep(5))-- to induce delays.
Actix-specific risk factors include:
- Handlers using
web::Pathorweb::QuerywithStringextraction (instead of typed primitives likei32) increase risk if input isn't validated. - Raw SQL usage with
sqlx::queryordieselwithout parameterization. - Error messages that leak SQL state (though blind iOS assumes no direct output).
Real-world parallels include CVE-2019-11043 (PHP-FPM) and Spring4Shell adjacent patterns where input traversal enables injection, though Actix-specific instances often stem from custom query building.
Actix-Specific Detection
Detecting blind SQL injection in Actix requires analyzing both code patterns and runtime behavior. Static analysis can flag unsafe string concatenation in SQL queries, but confirmation needs dynamic testing due to the blind nature. middleBrick identifies this through active probing of the unauthenticated attack surface during its 5–15 second scan.
During scanning, middleBrick sends sequential payloads to endpoints like /profile/{id}:
- Boolean-based:
' AND 1=1--and' AND 1=2--to detect response divergence (e.g., 200 vs 404). - Time-based:
' OR (SELECT pg_sleep(3))--to measure response time anomalies. - Error-based:
' AND (SELECT 1 FROM (SELECT COUNT(*),CONCAT((SELECT version()),FLOOR(RAND(0)*2))x FROM information_schema.tables GROUP BY x)a)--to provoke SQL errors if error messages are leaked.
For Actix applications, middleBrick prioritizes endpoints with:
- Path/query parameters used in data access layers.
- Responses varying by status code, body length, or timing.
- Absence of input validation middleware (e.g., no
actix-web::middleware::Loggerwith sanitization).
Example detection output from middleBrick CLI:
$ middlebrick scan https://api.example.com
[+] Scan complete. Security score: D (42/100)
[!] Finding: Blind SQL Injection in /profile/{id} (ID: MID-2024-001)
Severity: High
Evidence: Boolean-based divergence detected (payload ' AND 1=1-- returned 200, ' AND 1=2-- returned 404)
Remediation: Use parameterized queries via sqlx::query!() or diesel's query builder.
This detects the issue without agents, configuration, or credentials—just by submitting the URL. middleBrick maps findings to OWASP API Security Top 10 (A1:2023 Broken Object Level Authorization, though SQLi often underpins A3:2023 Injection) and provides CVSS-like severity scoring.
Actix-Specific Remediation
Fixing blind SQL injection in Actix applications requires eliminating unsanitized input in SQL queries using Actix-compatible libraries. The primary defense is parameterized queries via sqlx or diesel, which separate code from data. Input validation and typed extraction add defense-in-depth.
Refactor the vulnerable endpoint using sqlx's compile-time checked queries:
use actix_web::{get, web, HttpResponse, Responder};
use sqlx::PgPool;
#[derive(Debug, sqlx::FromRow)]
struct User {
id: i32,
name: String,
email: String,
}
#[get("/profile/{id}")]
async fn get_profile(pool: web::Data, id: web::Path) -> impl Responder {
match sqlx::query_as::<_, User>(
"SELECT id, name, email FROM users WHERE id = $1"
)
.bind(id.into_inner())
.fetch_one(pool.get_ref())
.await
{
Ok(user) => HttpResponse::Ok().json(user),
Err(sqlx::Error::RowNotFound) => HttpResponse::NotFound().finish(),
Err(_) => HttpResponse::InternalServerError().finish(),
}
}
Key fixes:
- Changed
web::Pathtoweb::Path—Actix automatically rejects non-numeric input with 400 Bad Request before reaching the handler. - Used
sqlx::query_as!with$1placeholder;sqlxhandles type-safe parameter binding. - Explicit error handling for
RowNotFoundvs other errors.
If using diesel, the equivalent is:
use actix_web::{get, web, HttpResponse, Responder};
use diesel::prelude::*;
use diesel::pg::PgConnection;
#[get("/profile/{id}")]
async fn get_profile(pool: web::Data, id: web::Path) -> impl Responder {
use crate::schema::users::dsl::*;
web::block(move || {
let mut conn = pool.get().expect("couldn't get db connection");
users.filter(id.eq(id.into_inner())).first::(&mut conn)
})
.await
.map(|user| HttpResponse::Ok().json(user))
.map_err(|_| HttpResponse::InternalServerError().finish())
}
Additional Actix-specific hardening:
- Apply
actix-web::middleware::Conditionwithactix-web::middleware::Loggerto log requests without logging raw user input. - Use
actix-web::web::Datato share a validated connection pool. - For legacy raw SQL, never use
format!orpush_str—always usesqlx::querywith parameters.
After fixing, rescan with middleBrick to verify the finding is resolved. The CLI returns JSON for CI/CD integration:
$ middlebrick scan https://api.example.com --format json
{"score": 92, "grade": "A", "findings": []}
This approach aligns with OWASP ASVS v4.0.3 (V5.3: Verify all SQL queries use parameterized statements) and prevents blind SQLi by design.
Frequently Asked Questions
Does middleBrick require authentication to test for blind SQL injection in Actix endpoints?
Can Actix's built-in extractors prevent blind SQL injection if I use String parameters?
web::Path or web::Query with raw SQL concatenation remains vulnerable regardless of Actix's extraction layer. The risk lies in how the extracted string is used in SQL—not in Actix's parsing. Always combine typed extraction (e.g., web::Path) with parameterized queries.