Open Redirect in Actix with Hmac Signatures
Open Redirect in Actix with Hmac Signatures — how this specific combination creates or exposes the vulnerability
An open redirect in an Actix web application using Hmac Signatures typically occurs when a redirect target is derived from user-controlled data and the Hmac is computed only over trusted parameters, or the signature does not cover the redirect URL. If the application accepts a URL or a path parameter from the request and uses it to form a redirect without strict validation, an attacker can supply a malicious external address.
Consider a pattern where the client provides both a url query parameter and a token query parameter. The server is expected to verify that the token is valid for the given URL before redirecting. If the Hmac is computed only over internal state (e.g., a record ID) and does not include the redirect URL, an attacker can supply a valid token with an arbitrary external URL, causing Actix to redirect unauthenticated users to a phishing site.
For example, imagine an Actix handler that reads url and token, verifies the token, and then performs HttpResponse::Found().append_header((http::header::LOCATION, url)). If the token generation logic does not bind the signature to the exact destination URL, the verification can pass while the redirect target is entirely controlled by the attacker. This is an open redirect because the application follows an unvalidated external location provided by the client.
In the context of Hmac Signatures, the vulnerability arises when the signed payload does not explicitly and canonically include the redirect target. If the signature covers only an identifier or timestamp, an attacker can keep the signature valid while changing the URL. Additionally, if the application does not enforce an allowlist of acceptable domains or a strict validation that the resolved destination belongs to the same origin, the open redirect persists despite the presence of cryptographic integrity checks.
Real-world impact includes phishing and malware distribution, as users are tricked into following a legitimate-looking link that leads to a malicious site. This pattern maps to OWASP API Top 10 A05:2023 — Security Misconfiguration and A01:2023 — Broken Access Control, because insufficient validation of cross-origin redirects can bypass expected access boundaries.
Hmac Signatures-Specific Remediation in Actix — concrete code fixes
To remediate open redirect risks in Actix when using Hmac Signatures, ensure the signature explicitly covers the redirect URL and that the application validates the target against a strict allowlist before performing the redirect.
Below is a concrete, syntactically correct example of signing and verifying a redirect URL in Actix using Hmac-SHA256. The signature is computed over a canonical representation of the URL and a secret key. The server validates both the signature and the URL before redirecting.
use actix_web::{web, HttpResponse, Result};
use hmac::{Hmac, Mac};
use sha2::Sha256;
use base64::Engine;
// type alias for Hmac-SHA256
type HmacSha256 = Hmac;
// Generate a signed redirect token for a given URL and secret
fn sign_redirect_url(url: &str, secret: &[u8]) -> String {
let mut mac = HmacSha256::new_from_slice(secret).expect("HMAC can take key of any size");
mac.update(url.as_bytes());
let result = mac.finalize();
let signature = result.into_bytes();
// url-safe base64 without padding
base64::engine::general_purpose::URL_SAFE_NO_PAD.encode(signature)
}
// Verify the signature and ensure the URL is allowed
fn verify_and_redirect(url: &str, token: &str, secret: &[u8], allowed_domains: &[&str]) -> Result<HttpResponse> {
// 1) Validate domain allowlist
let parsed = url::Url::parse(url).map_err(|_| actix_web::error::ErrorBadRequest("invalid url"))?;
let host = parsed.host_str().ok_or_else(|| actix_web::error::ErrorBadRequest("missing host"))?;
if !allowed_domains.contains(&host) {
return Err(actix_web::error::ErrorForbidden("domain not allowed"));
}
// 2) Recompute signature and compare in constant time
let mut mac = HmacSha256::new_from_slice(secret).expect("HMAC can take key of any size");
mac.update(url.as_bytes());
let expected_sig = mac.finalize().into_bytes();
let decoded_token = base64::engine::general_purpose::URL_SAFE_NO_PAD.decode(token)
.map_err(|_| actix_web::error::ErrorBadRequest("invalid token"))?;
// Use verify_slice for constant-time comparison
let mut mac_verify = HmacSha256::new_from_slice(secret).expect("HMAC can take key of any size");
mac_verify.update(url.as_bytes());
mac_verify.verify_slice(&decoded_token).map_err(|_| actix_web::error::ErrorForbidden("invalid signature"))?;
// 3) Safe redirect
Ok(HttpResponse::Found()
.append_header((http::header::LOCATION, url))
.finish())
}
// Example route
async fn redirect_handler(
web::Query(params): web::Query>,
) -> Result<HttpResponse> {
let url = params.get("url").ok_or_else(|| actix_web::error::ErrorBadRequest("missing url"))?;
let token = params.get("token").ok_or_else(|| actix_web::error::ErrorBadRequest("missing token"))?;
let secret = b"super-secret-key-do-not-commit";
let allowed_domains = ["app.example.com", "dashboard.example.com"];
verify_and_redirect(url, token, secret, &allowed_domains)
}
Key remediation practices:
- Include the exact redirect URL in the Hmac payload so any tampering invalidates the signature.
- Use a strict allowlist of domains or origins; do not rely on path-prefix checks alone.
- Always parse the URL to confirm the host and scheme, preventing open redirects via encoded or mixed-case schemes.
- Perform constant-time signature verification to avoid timing attacks.
- Avoid exposing raw user input in Location headers without canonicalization; normalize the URL before signing and verifying.
By binding the Hmac to the exact target URL and validating the destination against a known set of safe origins, the application prevents attackers from leveraging valid tokens to redirect users to arbitrary external sites.
FAQ
- q: Can an attacker bypass Hmac verification by modifying query parameters used in signing?
- a: Yes, if the Hmac does not cover the redirect URL parameter itself. Always include the exact destination URL in the signed payload and validate it against an allowlist before redirecting.
- q: Is using a referrer or origin check sufficient to prevent open redirects in Actix?
- a: No. Referrer and Origin headers can be omitted or spoofed. Combine signature-based integrity checks with explicit domain allowlists to reliably prevent open redirects.