Phishing Api Keys in Actix
How Phishing API Keys Manifests in Actix
Phishing API keys in Actix applications typically occurs through insecure API key handling in web service endpoints. Attackers exploit endpoints that accept API keys as query parameters or headers without proper validation, allowing credential harvesting through various attack vectors.
A common manifestation appears in Actix route handlers that accept API keys as query parameters. Consider this vulnerable pattern:
use actix_web::{web, App, HttpServer, HttpResponse, Responder};
async fn api_endpoint(
query: web::Query<serde_json::Value>,
data: web::Data<AppState>
) -> impl Responder {
let api_key = query.get("api_key").unwrap_or_default();
// No validation or rate limiting
if api_key == data.valid_api_key {
return HttpResponse::Ok().finish();
}
HttpResponse::Unauthorized().finish()
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| {
App::new()
.app_data(web::Data::new(AppState {
valid_api_key: "VALID_KEY".to_string()
}))
.service(web::resource("/api/data")
.route(web::get().to(api_endpoint)))
})
.bind("127.0.0.1:8080")?
.run()
.await
}
This pattern exposes API keys to multiple attack vectors. Query parameters appear in browser history, server logs, and referrer headers. An attacker can craft phishing URLs like /api/data?api_key=VALID_KEY and distribute them through various channels.
Another manifestation occurs when Actix applications use middleware for API key validation but implement it insecurely:
use actix_web::{dev::ServiceRequest, dev::ServiceResponse, HttpMessage};
async fn api_key_middleware(
req: ServiceRequest,
srv: &mut actix_web::dev::Service<ServiceRequest, ServiceResponse>
) -> actix_web::Result<ServiceResponse> {
let headers = req.headers();
let api_key = headers.get("x-api-key").unwrap_or_default();
// Vulnerable: no key validation, no rate limiting
if api_key.is_none() {
return Err(actix_web::error::ErrorUnauthorized("Missing API key"));
}
srv.call(req).await
}
This middleware accepts any API key without validating against a whitelist, making it trivial for attackers to use stolen or guessed keys.
Actix-Specific Detection
Detecting phishing API key vulnerabilities in Actix applications requires examining both code patterns and runtime behavior. middleBrick's scanning identifies these issues through black-box testing of unauthenticated endpoints.
Code-level detection focuses on these Actix-specific patterns:
use actix_web::{web, get, post, Responder};
#[get("/vulnerable/{api_key}")]
async fn vulnerable_route(path: web::Path<String>) -> impl Responder {
// Path parameter API key - visible in logs and browser history
let key = path.into_inner();
// No validation, no rate limiting
if key == "VALID" {
return HttpResponse::Ok().finish();
}
HttpResponse::BadRequest().finish()
}
#[post("/another_vulnerable")]
async fn another_vulnerable(
form: web::Form<serde_json::Value>
) -> impl Responder {
// Form data API key - appears in server logs
let api_key = form.get("api_key").unwrap_or_default();
// Missing validation logic
process_request(api_key);
HttpResponse::Ok().finish()
}
middleBrick's scanning detects these patterns by testing endpoints with various API key formats and monitoring responses. The scanner identifies endpoints that:
- Accept API keys without validation (returning 200 for any key)
- Expose API keys in URLs or headers without encryption
- Lack rate limiting on authentication endpoints
- Log API keys in plaintext
- Have inconsistent error messages revealing valid key status
Runtime detection involves monitoring for suspicious API key patterns in logs and network traffic. Actix applications should implement request logging that redacts API keys:
use actix_web::{dev::ServiceRequest, dev::ServiceResponse, HttpMessage};
async fn logging_middleware(
req: ServiceRequest,
srv: &mut actix_web::dev::Service<ServiceRequest, ServiceResponse>
) -> actix_web::Result<ServiceResponse> {
// Redact API keys before logging
let redacted_req = redact_api_keys(req.clone());
log::info!("Request: {:?}", redacted_req);
let res = srv.call(req).await?;
let redacted_res = redact_sensitive_data(res.clone());
log::info!("Response: {:?}", redacted_res);
Ok(res)
}
Actix-Specific Remediation
Securing Actix applications against phishing API key attacks requires implementing proper validation, rate limiting, and secure key management. The following remediation strategies use Actix's native features.
Implement secure API key validation using middleware with proper error handling:
use actix_web::{dev::ServiceRequest, dev::ServiceResponse, Error, HttpMessage};
use actix_web::http::header::HeaderName;
use std::collections::HashSet;
struct ApiKeyValidator {
valid_keys: HashSet<String>,
rate_limiter: actix_ratelimit::RateLimiter,
}
impl actix_web::dev::Transform<ServiceRequest, ServiceResponse> for ApiKeyValidator {
type Response = ServiceResponse;
type Error = Error;
type Future = actix_web::dev::ServiceCall<Self, ServiceRequest>;
fn new_transform(&self, service: ServiceRequest) -> Self::Future {
actix_web::dev::ServiceCall::new(self, service)
}
}
async fn validate_api_key(
req: ServiceRequest,
valid_keys: &HashSet<String>,
rate_limiter: &mut actix_ratelimit::RateLimiter
) -> Result<ServiceRequest, actix_web::Error> {
let headers = req.headers();
let api_key = headers.get("x-api-key").ok_or_else(|| {
actix_web::error::ErrorUnauthorized("Missing API key")
})?.to_str()?;
if !valid_keys.contains(api_key) {
return Err(actix_web::error::ErrorUnauthorized("Invalid API key"));
}
// Rate limiting per API key
let key = format!("apikey:{}", api_key);
if !rate_limiter.check(&key).await {
return Err(actix_web::error::ErrorTooManyRequests("Rate limit exceeded"));
}
Ok(req)
}
Store API keys securely using environment variables or secret management services:
use actix_web::{get, Responder, web};
use serde::Deserialize;
#[derive(Deserialize)]
struct ApiConfig {
api_keys: Vec<String>,
}
#[get("/secure-endpoint")]
async fn secure_endpoint(
config: web::Data<ApiConfig>,
req: actix_web::HttpRequest
) -> impl Responder {
let headers = req.headers();
let api_key = headers.get("x-api-key").ok_or("Missing API key");
if !config.api_keys.contains(&api_key.unwrap().to_str().unwrap()) {
return HttpResponse::Unauthorized().finish();
}
// Process request
HttpResponse::Ok().finish()
}
Implement comprehensive logging with API key redaction:
use actix_web::{dev::ServiceRequest, dev::ServiceResponse, HttpMessage};
use slog::{Logger, o};
async fn secure_logging_middleware(
req: ServiceRequest,
srv: &mut actix_web::dev::Service<ServiceRequest, ServiceResponse>,
logger: &Logger
) -> actix_web::Result<ServiceResponse> {
let mut redacted_req = req.clone();
if let Some(header) = redacted_req.headers_mut().get_mut("x-api-key") {
*header = actix_web::http::HeaderValue::from_static("REDACTED");
}
logger.info!("Request received"; "method" => format!("{:?}", req.method()), "path" => format!("{:?}", req.uri()));
let res = srv.call(req).await?;
logger.info!("Request completed"; "status" => res.status().as_u16());
Ok(res)
}