Cache Poisoning in Actix with Bearer Tokens
Cache Poisoning in Actix with Bearer Tokens — how this specific combination creates or exposes the variation
Cache poisoning occurs when an attacker manipulates cached responses so that malicious content is served to other users. In Actix-based APIs that use Bearer Tokens for authorization, this risk arises when authorization data is inadvertently reflected in cache keys or cached responses. If a server varies cache by the Authorization header but the token is treated as part of the request identity without proper normalization, an authenticated request containing a Bearer Token can leave a cached response that is later served to a different user who shares the same effective cache key except for the token.
Consider an Actix web service that caches user profile data. If the caching layer uses the full request URI plus the Authorization header as the cache key, two users with different tokens but access to the same resource will each store separate cached copies. This is not inherently unsafe, but misconfiguration can occur if the service accidentally caches a response from a privileged user and serves it to a less privileged user whose URI matches yet token does not. In such a setup, the cached response may still contain sensitive user-specific fields or an Authorization header fragment, leading to information disclosure. This becomes more pronounced if the backend varies cache by custom headers such as Authorization but fails to validate that the token does not affect the response content for a given resource.
Another scenario involves query parameters that interact with Authorization headers. An endpoint like /api/v1/profile?details=full might be cached with a key that includes the Bearer Token. If token handling in Actix middleware does not strip or normalize the Authorization header before caching, an attacker who can observe or influence one user’s cached entry might infer relationships or cause a poisoned cache entry to be stored. This is a cache poisoning vector because the cached response is tied to a specific token, yet may be reused under certain routing or reverse-proxy rules that do not preserve token isolation.
Actix applications that rely on HTTP caching at the edge or within the application must ensure that any sensitive header, including Bearer Tokens, is excluded from cache key construction. The framework itself does not inherently cache responses; however, integrations with caching middleware or reverse proxies can introduce these risks if headers are inadvertently included. Security checks that validate correct use of the Authorization header and ensure it does not leak into cache decisions are essential to prevent cross-user data exposure.
Bearer Tokens-Specific Remediation in Actix — concrete code fixes
To mitigate cache poisoning when using Bearer Tokens in Actix, ensure that the Authorization header is never used as part of the cache key and that responses containing sensitive data are not cached for different users. Below are concrete remediation steps and code examples.
1. Exclude Authorization header from cache key
When integrating with a caching layer, configure the cache to ignore the Authorization header. If you are using middleware in Actix to control caching, ensure the header is stripped before generating the cache identifier.
use actix_web::{dev::ServiceRequest, Error};
use actix_web_httpauth::extractors::bearer::BearerAuth;
async fn cache_key_middleware(
req: ServiceRequest,
cache_key: &mut String,
) -> Result<(), Error> {
// Intentionally omit Authorization from cache key
let uri = req.uri().path_and_query().map(|v| v.as_str()).unwrap_or("/");
*cache_key = format!("{}?user_role=public", uri);
Ok(())
}
2. Vary cache by user ID, not token
If user-specific caching is required, derive the cache key from a user identifier extracted securely from the token payload, not from the token string itself. This ensures that different tokens for the same user map to the same cache entry, while tokens for different users do not share cached responses.
use actix_web::{web, HttpRequest};
use jsonwebtoken::{decode, Algorithm, DecodingKey, Validation};
async fn get_user_cache_key(req: &HttpRequest) -> Option {
let auth_header = req.headers().get("authorization")?;
let auth_str = auth_header.to_str().ok()?.strip_prefix("Bearer ")?;
// Decode token without validating signature for cache purposes; use public key
let token_data = decode::(
auth_str,
&DecodingKey::from_secret(include_bytes!("secret.key")),
&Validation::new(Algorithm::HS256),
).ok()?;
Some(format!("user:{}", token_data.claims.sub))
}
3. Set explicit cache-control headers for authenticated responses
Ensure that responses containing sensitive data include cache-control directives that prevent caching across users. In Actix, you can set headers on responses to enforce no-store or private caching.
use actix_web::{HttpResponse, http::header};
fn private_user_response() -> HttpResponse {
HttpResponse::Ok()
.insert_header((header::CACHE_CONTROL, "no-store"))
.json(serde_json::json!({
"profile": "sensitive_data"
}))
}
4. Validate Authorization header usage in route guards
Ensure that routes requiring authentication properly validate Bearer Tokens and do not allow unauthenticated access to cached endpoints. Use Actix guards to enforce that only requests with valid tokens can access certain paths, reducing the chance of a cached unauthenticated response being served.
use actix_web::middleware::Logger;
use actix_web_httpauth::middleware::HttpAuthentication;
use actix_web::App;
fn auth_validator() -> HttpAuthentication {
let bearer = HttpAuthentication::bearer(|req, credentials| {
// Validate token here; reject if invalid
if credentials.token() == "valid_token_123" {
Ok(())
} else {
Err(actix_web::error::ErrorUnauthorized("Invalid token"))
}
});
bearer
}
// In your App configuration
App::new()
.wrap(Logger::default())
.service(
web::resource("/api/secure")
.wrap(auth_validator())
.to(secure_handler)
)
By excluding Bearer Tokens from cache keys, normalizing cache by user identity, and enforcing strict cache-control headers, you reduce the risk of cache poisoning in Actix applications. These practices ensure that sensitive authorization data does not inadvertently influence caching behavior.