HIGH cache poisoningactixhmac signatures

Cache Poisoning in Actix with Hmac Signatures

Cache Poisoning in Actix with Hmac Signatures — how this specific combination creates or exposes the variation

Cache poisoning occurs when an attacker causes a cache to store malicious content, leading other users to receive that content. In Actix-based services that use Hmac Signatures to authenticate requests, misconfiguration or weak validation can allow an unauthenticated or low-privilege actor to inject a variant into the cache key. When the cache treats the tainted request as cacheable and serves the poisoned entry to other users, the Hmac Signature does not prevent this because the signature is often verified after cache lookup or only applied to specific parts of the request.

Consider an endpoint that normalizes query parameters but does not include the full signed payload in the cache key. An attacker can send a request with a valid Hmac Signature for one set of parameters, while also injecting an additional parameter that changes the response meaning. If the cache key excludes that injected parameter or only hashes a subset of headers/query params, the poisoned variant can be cached. Subsequent requests for the "clean" parameters may receive the attacker-controlled response, leading to content manipulation or unauthorized data disclosure.

Real-world examples include scenarios where the Vary header is not respected, or where the cache key is derived from a subset of the request that excludes signature-verified fields. This is especially relevant when using shared caches or when upstream services behind Actix do not independently validate authorization. The Hmac Signature ensures request integrity between client and server, but it does not automatically protect cached representations unless the cache key explicitly incorporates all inputs that influence the response and those inputs are verified before caching.

Additionally, if the signature verification occurs post-cache lookup, an attacker who can cause cache misses with injected parameters may leverage timing or error handling to learn about valid signatures or induce cache fragmentation. Even with Hmac Signatures properly implemented, failing to canonicalize inputs and include them in the cache key exposes the application to cache poisoning via variant manipulation.

Hmac Signatures-Specific Remediation in Actix — concrete code fixes

To mitigate cache poisoning when using Hmac Signatures in Actix, ensure the cache key includes all request dimensions that affect the response and that signature verification occurs before any caching decision. Use a strong canonicalization strategy and avoid omitting parameters or headers from the key.

Example: Safe cache key construction with Hmac Signatures in Actix

use actix_web::{web, HttpRequest, HttpResponse, Result};
use hmac::{Hmac, Mac};
use sha2::Sha256;
use std::collections::BTreeMap;

type HmacSha256 = Hmac;

/// Build a canonical query string from sorted key-value pairs
fn canonical_query(params: &BTreeMap) -> String {
    params
        .iter()
        .map(|(k, v)| format!("{}={}", k, v))
        .collect::>()
        .join("&")
}

/// Compute Hmac signature for a payload
fn compute_hmac(key: &[u8], payload: &str) -> String {
    let mut mac = HmacSha256::new_from_slice(key).expect("HMAC can take key of any size");
    mac.update(payload.as_bytes());
    let result = mac.finalize();
    let code = result.into_bytes();
    hex::encode(code)
}

/// Extract and verify Hmac signature from headers, then build cache key
async fn handle_request(req: HttpRequest, query: web::Query>) -> Result {
    let signature = req.headers().get("X-Api-Signature")
        .and_then(|v| v.to_str().ok())
        .ok_or_else(|| actix_web::error::ErrorBadRequest("Missing signature"))?;

    // Canonicalize query parameters (sorted)
    let canonical = canonical_query(&query);
    let payload = format!("GET /api/resource?{}", canonical);

    // Verify Hmac before using any request-derived data for caching
    let secret = b"super-secret-key"; // load securely in production
    let computed = compute_hmac(secret, &payload);
    if !hmac::verify(secret, payload.as_bytes(), signature.as_bytes()).is_ok() {
        return Err(actix_web::error::ErrorUnauthorized("Invalid signature"));
    }

    // Cache key must include all inputs that affect the response
    let cache_key = format!("v1:resource:{}:sig:{}", canonical, signature);

    // Proceed to fetch or compute response, then store under cache_key
    Ok(HttpResponse::Ok().body(format!("Cached key: {}", cache_key)))
}

Example: Enforce Vary and include signature-influenced inputs

use actix_web::http::header::HeaderValue;
use actix_web::HttpResponseBuilder;

/// Build response with appropriate Vary header to prevent cache key collisions
fn build_response_with_vary() -> HttpResponseBuilder {
    let mut resp = HttpResponse::Ok();
    // Vary on the full set of inputs that change the representation
    resp.insert_header(("Vary", "X-Api-Signature, Authorization, Accept-Encoding"))
}

Key remediation steps:

  • Include all request dimensions that affect the response in the cache key, especially query parameters, selected headers, and the Hmac signature value used for verification.
  • Perform Hmac signature verification before consulting or writing to the cache to ensure only authenticated and authorized variants are cached.
  • Use a canonical parameter ordering (e.g., sorted keys) to ensure consistent cache keys for semantically identical requests.
  • Set a Vary header that reflects the dimensions used in the cache key so shared caches do not serve mismatched representations.
  • Avoid including user-specific data in shared cache keys unless the cache is partitioned per user or the data is safe to share.

Frequently Asked Questions

Why doesn't Hmac Signature verification alone prevent cache poisoning in Actix?
Hmac Signatures ensure request integrity between client and server, but they do not automatically protect cached representations. If the cache key excludes parameters that the signature covers or if verification occurs after cache lookup, an attacker can inject a variant that gets cached and served to other users.
What is a minimal, concrete mitigation for cache poisoning in Actix with Hmac Signatures?
Include all inputs that affect the response (e.g., sorted query parameters and the signature value) in the cache key, verify the Hmac signature before using any request-derived data for caching, and set a Vary header that reflects those inputs.