Rainbow Table Attack in Actix with Cockroachdb
Rainbow Table Attack in Actix with Cockroachdb — how this specific combination creates or exposes the vulnerability
A rainbow table attack leverages precomputed hashes to reverse lookup credentials. In an Actix-web service using CockroachDB as the backing store, the risk arises when password-equivalent values are stored without a unique, high-entropy salt per user and when authentication endpoints are unauthenticated or weakly rate-limited. middleBrick scans for these conditions as part of its Authentication and BOLA/IDOR checks, noting that attackers can target unauthenticated Actix endpoints to retrieve or infer account data that can be matched against a rainbow table offline.
Consider an Actix endpoint that performs a lookup by email and returns a password hash stored in CockroachDB. If the hash is unsalted or uses a low-work factor, and the endpoint does not enforce rate limiting or require authentication, middleBrick’s parallel checks for Rate Limiting, Authentication, and Data Exposure may flag the risk. An attacker can probe the endpoint with many emails, extract the hashes, and compare them against a rainbow table to recover passwords. This is especially relevant when OpenAPI/Swagger specs expose the authentication surface without specifying strong hashing parameters; middleBrick cross-references the spec definitions with runtime findings to highlight weak cryptographic practices.
The combination of Actix routing, CockroachDB storage, and missing controls can unintentionally expose password material. For example, if the application uses deterministic hashing (e.g., unsalted SHA256) and the endpoint is reachable without credentials, an authenticated attacker (or an unauthenticated one if authorization is misconfigured) can enumerate users and obtain hashes to attack offline. middleBrick’s BOLA/IDOR and Authentication checks look for missing or weak authorization on data retrieval paths, while its Data Exposure and Encryption checks verify whether strong, salted hashing is enforced in the database schema and application code.
Cockroachdb-Specific Remediation in Actix — concrete code fixes
Remediation centers on ensuring each user has a unique salt, using a strong key-derivation function, and protecting endpoints with authentication and rate limiting. In CockroachDB, store a per-user salt alongside the derived key, and use algorithms like Argon2id or bcrypt. Below are concrete, working examples for an Actix-web service with CockroachDB (using sqlx).
1. Database schema with per-user salt
CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
email TEXT UNIQUE NOT NULL,
password_hash TEXT NOT NULL,
password_salt TEXT NOT NULL
);
2. User registration with salt and Argon2id
use argon2::{Argon2, PasswordHasher, PasswordVerifier, Params};
use sqlx::PgPool;
use uuid::Uuid;
async fn register_user(email: &str, password: &str, pool: &PgPool) -> Result<(), sqlx::Error> {
let salt: String = Uuid::new_v4().to_string(); // unique salt per user
let argon2 = Argon2::new(
argon2::Algorithm::Argon2id,
argon2::Version::V0x13,
Params::new(15000, 2, 1, Some(32)).unwrap(),
);
let password_hash = argon2.hash_password(password.as_bytes(), salt.as_bytes())
.expect("hashing failed")
.to_string();
sqlx::query!(
r#"INSERT INTO users (email, password_hash, password_salt) VALUES ($1, $2, $3)"#,
email,
password_hash,
salt
)
.execute(pool)
.await?;
Ok(())
}
3. Login with constant-time verification and rate limiting in Actix
use actix_web::{post, web, HttpResponse, Result};
use sqlx::FromRow;
use std::time::Instant;
#[derive(FromRow)]
struct UserRecord {
password_hash: String,
password_salt: String,
}
async fn verify_login(
email: &str,
password_attempt: &str,
pool: &PgPool,
) -> Result {
let user: UserRecord = sqlx::query_as(&format!(
r#"SELECT password_hash, password_salt FROM users WHERE email = $1"#
))
.bind(email)
.fetch_one(pool)
.await?;
let argon2 = Argon2::new(
argon2::Algorithm::Argon2id,
argon2::Version::V0x13,
Params::new(15000, 2, 1, Some(32)).unwrap(),
);
// Use the stored salt; this is safe as verification is constant-time in Argon2
let valid = argon2.verify_password(
password_attempt.as_bytes(),
user.password_salt.as_bytes(),
)
.is_ok();
Ok(valid)
}
#[post("/login")]
async fn login(
form: web::Form<LoginForm>,
pool: web::Data<PgPool>,
rate_limiter: web::Data<RateLimiter>,
) -> Result<HttpResponse> {
// Enforce rate limiting before checking credentials
if !rate_limiter.check(&form.email).await {
return Ok(HttpResponse::TooManyRequests().finish());
}
match verify_login(&form.email, &form.password, &pool).await {
Ok(true) => Ok(HttpResponse::Ok().finish()),
Ok(false) => Ok(HttpResponse::Unauthorized().finish()),
Err(_) => Ok(HttpResponse::InternalServerError().finish()),
}
}
4. Additional protections highlighted by middleBrick
- Ensure the authentication endpoint requires credentials where appropriate to prevent unauthenticated enumeration.
- Apply rate limiting at the Actix middleware level to mitigate brute-force and rainbow table lookup attempts.
- Use TLS to protect hashes in transit; middleBrick’s Encryption check can verify this.
- Regularly review the OpenAPI spec with middleBrick’s scan to ensure hashing parameters and auth requirements are explicitly defined and enforced.