MEDIUM clickjackingaxumjwt tokens

Clickjacking in Axum with Jwt Tokens

Clickjacking in Axum with Jwt Tokens — how this specific combination creates or exposes the vulnerability

Clickjacking is a client-side UI redressing attack where an attacker tricks a user into interacting with a hidden or disguised element inside an invisible or disguised iframe. When an API serving authenticated views relies solely on JWT Tokens for authorization without additional anti-clickjacking protections, a browser-based session can be abused even if the token itself is not leaked. In Axum, if an endpoint returns HTML for a logged-in user and sets the JWT Token only in an Authorization header (e.g., Bearer), the application may still render pages that lack frame-busting or CSP frame-ancestors rules. An attacker can host a page that embeds your Axum application in an iframe and overlay invisible controls or misleading UI, causing a user with a valid JWT Token to perform unintended actions on your behalf.

The risk is compounded when JWT Tokens are used for session-like behavior in browser-rendered views (e.g., Single Page Applications or server-rendered pages with cookie-based fallback). If your Axum app embeds third-party content or exposes an admin UI accessible via predictable routes, an attacker may craft a malicious site that loads your routes inside an iframe, leveraging the user’s valid JWT Token sent automatically by the browser (if cookies are also used) or via crafted requests. Because middleBrick does not test for UI framing issues directly, you should validate that pages requiring authorization do not expose clickjacking surfaces, especially when JWT Tokens are used alongside cookies or when CORS is permissive.

For example, an endpoint like GET /admin/settings that returns an HTML page protected only by JWT Token validation in the Authorization header can be embedded maliciously if the response lacks proper frame control headers. Attackers can combine this with social engineering to induce clicks on hidden elements, changing settings or initiating state-changing requests. The presence of JWT Tokens does not prevent framing; it only authenticates the request. Therefore, defense requires explicit frame-ancestor policies and careful design of which responses are allowed to be framed.

Jwt Tokens-Specific Remediation in Axum — concrete code fixes

Remediation focuses on preventing your Axum application from being framed and ensuring that responses carrying JWT Tokens are not usable in an embedded context unless explicitly intended. Below are concrete Axum examples that combine frame protection headers with JWT Token validation middleware.

1. Frame protection via headers in Axum

Set Content-Security-Policy frame-ancestors to disallow embedding, and include X-Frame-Options for legacy browser compatibility. These headers should be applied to responses that could render in a browser, even when JWT Tokens are used for authentication.

use axum::{routing::get, Router};
use std::net::SocketAddr;
use axum::http::HeaderValue;

async fn settings() -> String {
    "Protected settings".to_string()
}

#[tokio::main]
async fn main() {
    let app = Router::new()
        .route("/admin/settings", get(settings))
        .layer(axum::middleware::from_fn(|axum::middleware::Next(req| {
            async move {
                let mut res = req.run().await?;
                // Prevent framing regardless of JWT Token usage
                res.headers_mut().insert(
                    "Content-Security-Policy",
                    HeaderValue::from_static("frame-ancestors 'self'"),
                );
                res.headers_mut().insert(
                    "X-Frame-Options",
                    HeaderValue::from_static("DENY"),
                );
                Ok(res)
            }
        })));

    let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
    axum::Server::bind(&addr)
        .serve(app.into_make_service())
        .await
        .unwrap();
}

2. JWT Token validation combined with per-route authorization

Ensure that JWT Token validation is performed before serving sensitive routes, and that token usage does not implicitly permit framing. Below is an example using a middleware that validates a bearer token and conditionally allows the request to proceed, while still applying frame controls.

use axum::{routing::get, Router, extract::Request, http::StatusCode};
use jsonwebtoken::{decode, Algorithm, DecodingKey, Validation, TokenData};
use serde::{Deserialize, Serialize};

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

async fn validate_jwt(req: Request) -> Result<TokenData<Claims>, (StatusCode, String)> {
    let auth = req.headers().get("authorization")
        .and_then(|v| v.to_str().ok())
        .and_then(|s| s.strip_prefix("Bearer "))
        .ok_or((StatusCode::UNAUTHORIZED, "Missing or invalid Authorization header".into()))?;

    let token_data = decode::

3. Apply frame controls selectively to API responses that render HTML

If your Axum service also exposes JSON APIs that return JWT Tokens or are consumed by clients that do not render HTML, do not apply frame headers to those endpoints unless they also serve HTML. This minimizes unintended side effects while protecting browser-based sessions.

Frequently Asked Questions

Do JWT Tokens prevent clickjacking if they are transmitted in the Authorization header?
No. JWT Tokens authenticate requests but do not prevent a page from being embedded in an iframe. You must set frame-ancestors (CSP) and/or X-Frame-Options to protect against clickjacking, regardless of how tokens are transmitted.
Should I include frame-ancestors in responses that only return JSON and JWT Tokens?
No. Frame controls are only relevant for responses that are rendered in a browser. Apply Content-Security-Policy frame-ancestors and X-Frame-Options to HTML responses or pages that could be loaded in an iframe; omit them for pure JSON API responses to avoid unnecessary header overhead.