HIGH dns cache poisoningactixjwt tokens

Dns Cache Poisoning in Actix with Jwt Tokens

Dns Cache Poisoning in Actix with Jwt Tokens — how this specific combination creates or exposes the vulnerability

DNS cache poisoning (also known as DNS spoofing) occurs when an attacker injects a fraudulent DNS response into a resolver’s cache, causing subsequent requests for a domain to resolve to an attacker-controlled IP. In an Actix-based API that relies on JWT tokens for authentication and authorization, this vector can undermine trust boundaries even when tokens are cryptographically validated.

Consider an Actix web service that performs service-to-service calls to an internal identity provider using a hostname (e.g., auth.internal.example.com). If the runtime environment’s DNS resolver is poisoned, the hostname may resolve to a malicious host. The Actix service, trusting DNS-derived endpoints, may then send or accept JWT tokens over a network path controlled by an attacker. This can facilitate token interception or token replay if the transport is not strictly enforced to use a verified, non-DNS-derived endpoint. While JWT signatures protect token integrity, they do not prevent the act of sending the token to an unintended party when DNS resolution is subverted.

Additionally, if an Actix service exposes an unauthenticated endpoint that returns internal metadata or configuration and that endpoint’s hostname is resolved via DNS, an attacker may poison DNS to redirect metadata requests to a malicious server. A client obtaining metadata (even without tokens) might then be tricked into using a malicious issuer URL for JWT validation, enabling issuer substitution attacks if the client does not strictly validate the issuer claim against a pinned value. This is especially relevant when the JWT validation logic dynamically fetches JWKS endpoints by hostname, and that hostname is resolved via DNS at runtime.

In practice, this risk is not inherent to JWT itself but arises when identity resolution and token validation workflows depend on DNS without additional safeguards such as certificate pinning, strict issuer validation, or static endpoint configuration. Actix applications that integrate with external identity providers must ensure that the validation chain—issuer, JWKS endpoint, and token introspection paths—is not dependent on mutable DNS records susceptible to cache poisoning.

Jwt Tokens-Specific Remediation in Actix — concrete code fixes

Remediation focuses on removing reliance on DNS for security-critical decisions and enforcing strict validation of JWT claims and endpoints. Below are concrete patterns for Actix applications using the jsonwebtoken crate.

1. Use static, non-DNS endpoints for JWKS and issuer validation

Instead of resolving the JWKS URI at runtime, embed the full HTTPS URL (including host) in configuration. This prevents an attacker from redirecting key discovery via DNS poisoning.

use jsonwebtoken::{decode, Algorithm, DecodingKey, Validation, TokenData, Header};
use serde::{Deserialize, Serialize};

#[derive(Debug, Serialize, Deserialize)]
struct Claims {
    sub: String,
    iss: String,
    exp: usize,
}

async fn validate_token_static(token: &str) -> Result {
    // Static, non-DNS endpoint for issuer and JWKS; no runtime host resolution
    const EXPECTED_ISSUER: &str = "https://auth.example.com/";
    const JWKS_URI: &str = "https://auth.example.com/.well-known/jwks.json";

    // In practice, fetch JWKS once at startup and reuse DecodingKey; here simplified
    let mut validation = Validation::new(Algorithm::RS256);
    validation.set_issuer(&[EXPECTED_ISSUER]);
    validation.validate_exp = true;

    let key = DecodingKey::from_rsa_pem(include_bytes!("./public_key.pem"))?;
    decode::(token, &key, &validation)
}

2. Pin the issuer and enforce strict hostname matching

Ensure the iss claim matches an exact expected value and avoid concatenating dynamic hostnames into issuer or JWKS discovery logic.

async fn validate_token_with_strict_issuer(token: &str) -> Result<TokenData<Claims>, &'static str> {
    const EXPECTED_ISSUER: &str = "https://auth.example.com/";
    let mut validation = Validation::new(Algorithm::RS256);
    validation.validate_exp = true;
    // jsonwebtoken crate validates issuer if set via set_issuer
    validation.set_issuer(&[EXPECTED_ISSUER]);

    let key = DecodingKey::from_rsa_pem(include_bytes!("./public_key.pem"));
    match key {
        Ok(k) => {
            let token_data = decode::<Claims>(token, &k, &validation);
            match token_data {
                Ok(data) => {
                    // Double-check issuer in claims matches pinned value
                    if data.claims.iss == EXPECTED_ISSUER {
                        Ok(data)
                    } else {
                        Err("issuer mismatch")
                    }
                }
                Err(e) => Err("invalid token"),
            }
        }
        Err(_) => Err("invalid key"),
    }
}

3. Avoid runtime hostname concatenation for security-sensitive URLs

Do not build JWKS URLs or issuer strings by concatenating user input or environment-derived hostnames. If dynamic discovery is required (not recommended), perform additional verification such as pinning a certificate or fingerprint.

// Anti-pattern to avoid:
// let jwks_uri = format!("https://{}/.well-known/jwks.json", dynamic_host);
// Prefer:
// const JWKS_URI: &str = "https://auth.example.com/.well-known/jwks.json";

4. Enforce HTTPS and certificate verification

Ensure HTTP clients used for any necessary introspection (if any) enforce TLS server certificate validation and do not fall back to HTTP. This prevents on-path DNS manipulation from downgrading the protocol.

5. Use Actix middleware to validate tokens early

Validate JWTs in an Actix extractor or middleware before routing, and reject requests with invalid or missing tokens. Keep validation logic independent of runtime DNS lookups.

use actix_web::{dev::ServiceRequest, Error, HttpMessage};
use actix_web_httpauth::extractors::bearer::BearerAuth;

async fn validate_jwt_middleware(req: ServiceRequest) -> Result<ServiceRequest, Error> {
    let auth_header = req.headers().get("authorization");
    // extract and validate token; reject if invalid
    // If validation requires external data, use a static, pinned configuration
    Ok(req)
}

Frequently Asked Questions

Can DNS cache poisoning redirect JWT validation requests to a malicious server?
Yes, if your Actix application resolves JWKS endpoints or issuer URLs via DNS at runtime, DNS cache poisoning can redirect those requests, enabling issuer substitution or key confusion. Mitigate by using static, pinned endpoints and strict issuer validation.
Does JWT signature validation prevent DNS cache poisoning?
No. JWT signatures protect token integrity, but they do not prevent an attacker from intercepting or redirecting the token itself via DNS manipulation. Transport security and endpoint authenticity must be enforced independently.