HIGH missing authenticationactixhmac signatures

Missing Authentication in Actix with Hmac Signatures

Missing Authentication in Actix with Hmac Signatures

Actix is a widely used Rust web framework where developers often choose HMAC signatures to authenticate HTTP requests. The vulnerability arises when endpoints that should be protected rely only on signature verification but do not enforce authentication checks for every request. In such cases, an attacker can send requests with valid HMAC headers derived from leaked or weak secrets, or send requests without any signature at all if the verification middleware is inconsistently applied.

Consider an Actix web service that uses HMAC-SHA256 to sign a subset of endpoints while leaving others open. If the developer fails to consistently apply authentication guards, the unauthenticated attack surface expands. For example, a health check or status endpoint might skip middleware, allowing an unauthenticated caller to learn whether the service is running or to probe for misconfigurations. Even when signatures are used, if the application does not require authentication for all sensitive routes, an attacker can exploit the missing authentication gap to invoke business logic that should be restricted.

During a middleBrick scan, which tests the unauthenticated attack surface in black-box mode, such inconsistencies are detected. The scanner checks whether endpoints that accept HMAC-signed requests also require authentication for unauthenticated calls. It looks for routes that lack guards, or where the signature verification passes but no downstream authorization is enforced. This can lead to unauthorized data access or operations, even when HMAC is present, because the missing authentication control bypasses intended access restrictions.

Real-world attack patterns mirror this class of risk. For instance, an attacker might send GET requests to administrative or data-export endpoints that mistakenly skip authentication checks, relying on obscurity rather than strict controls. In scenarios where HMAC is used for idempotency or replay protection but not paired with mandatory authentication, the system remains vulnerable to unauthorized invocation. Findings from a scan will highlight routes with missing authentication requirements and provide remediation guidance focused on ensuring that every sensitive path enforces authentication consistently, regardless of the presence of HMAC signatures.

Hmac Signatures-Specific Remediation in Actix

To remediate missing authentication in Actix when HMAC signatures are in use, ensure that every route that handles sensitive operations requires authentication, and that signature verification is applied consistently. Do not rely on signature presence alone; combine it with explicit authentication checks so that missing or malformed credentials are rejected even if the signature is valid.

Below are concrete, working examples for an Actix application using HMAC-SHA256. The first example shows a middleware guard that validates the HMAC signature and also enforces authentication. The second example demonstrates how to apply this guard selectively to routes that require protection, while keeping public routes accessible.

use actix_web::{web, App, HttpResponse, HttpServer, Responder, dev::ServiceRequest, Error};
use actix_web::http::header::HeaderValue;
use actix_web::middleware::Next;
use hmac::{Hmac, Mac};
use sha2::Sha256;
use std::collections::HashMap;

type HmacSha256 = Hmac;

async fn verify_hmac(
    req: ServiceRequest,
    credentials: web::Data>,
    mut payload: web::Payload,
    next: Next<'_>,
) -> Result {
    let path = req.path();
    let method = req.method().clone();
    let headers = req.headers();

    let timestamp = headers.get("X-Timestamp")
        .ok_or_else(|| actix_web::error::ErrorUnauthorized("missing timestamp"))?;
    let signature_header = headers.get("X-Signature")
        .ok_or_else(|| actix_web::error::ErrorUnauthorized("missing signature"))?;

    let key = credentials.get("hmac_secret")
        .ok_or_else(|| actix_web::error::ErrorUnauthorized("server misconfiguration"))?;
    let mut mac = HmacSha256::new_from_slice(key.as_bytes())
        .map_err(|_| actix_web::error::ErrorUnauthorized("hmac init failed"))?;

    // Construct the data to verify: method, path, timestamp, and body if present
    let body = match req.get_payload().next().await {
        Some(Ok(chunk)) => { mac.update(&chunk); chunk.to_vec() },
        _ => vec![],
    };
    mac.update(method.as_str().as_bytes());
    mac.update(path.as_bytes());
    mac.update(timestamp.as_bytes());

    let expected = mac.finalize();
    let result = expected.verify_slice(signature_header.as_bytes());

    if result.is_err() {
        return Err(actix_web::error::ErrorUnauthorized("invalid signature"));
    }

    // Ensure the request is authenticated (e.g., check an auth token or session)
    // In practice, you would validate an API key, JWT, or session here.
    // For this example, we assume a header "X-Auth-Token" is required alongside HMAC.
    let auth_token = headers.get("X-Auth-Token")
        .ok_or_else(|| actix_web::error::ErrorUnauthorized("missing auth token"))?;
    if auth_token != "expected_public_key_or_valid_session" {
        return Err(actix_web::error::ErrorUnauthorized("unauthorized"));
    }

    next.call(req).await
}

async fn public_endpoint() -> impl Responder {
    HttpResponse::Ok().body("Public info, no auth required")
}

async fn admin_endpoint() -> impl Responder {
    HttpResponse::Ok().body("Admin data")
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    let mut credentials = HashMap::new();
    credentials.insert("hmac_secret".to_string(), "supersecretvalue123".to_string());

    HttpServer::new(move || {
        App::new()
            .app_data(web::Data::new(credentials.clone()))
            .service(
                web::resource("/public")
                    .route(web::get().to(public_endpoint))
            )
            .service(
                web::resource("/admin")
                    .route(web::get().to(admin_endpoint))
                    .wrap_fn(|req, srv| {
                        verify_hmac(req, web::Data::new(credentials.clone()), srv)
                    })
            )
    })
    .bind("127.0.0.1:8080")?
    .run()
    .await
}

In this example, /admin requires both a valid HMAC signature and an explicit authentication token, ensuring that missing authentication is not bypassed by a correct signature. The HMAC verification uses method, path, timestamp, and body to prevent replay and tampering. For broader protection, apply the same verify_hmac guard to all sensitive routes and keep public endpoints separate. middleBrick can detect whether routes inconsistently require authentication and will surface these gaps with prioritized findings and remediation steps.

Related CWEs: authentication

CWE IDNameSeverity
CWE-287Improper Authentication CRITICAL
CWE-306Missing Authentication for Critical Function CRITICAL
CWE-307Brute Force HIGH
CWE-308Single-Factor Authentication MEDIUM
CWE-309Use of Password System for Primary Authentication MEDIUM
CWE-347Improper Verification of Cryptographic Signature HIGH
CWE-384Session Fixation HIGH
CWE-521Weak Password Requirements MEDIUM
CWE-613Insufficient Session Expiration MEDIUM
CWE-640Weak Password Recovery HIGH

Frequently Asked Questions

Can HMAC signatures alone prevent missing authentication issues in Actix?
No. HMAC signatures help ensure request integrity and authenticity, but they do not replace explicit authentication checks. If a route does not require authentication, an attacker can still invoke it even when HMAC is present. Always combine signature verification with mandatory authentication for sensitive endpoints.
How does middleBrick detect missing authentication in Actix APIs using HMAC?
middleBrick scans unauthenticated attack surfaces and checks whether protected routes require authentication. It flags routes that accept HMAC-signed requests but do not enforce authentication, and it cross-references spec definitions with runtime behavior to highlight inconsistent or missing controls.