MEDIUM clickjackingaxum

Clickjacking in Axum

How Clickjacking Manifests in Axum

Clickjacking in Axum applications occurs when malicious sites embed your API endpoints or web interfaces in invisible iframes, tricking users into performing unintended actions. Unlike traditional web applications where clickjacking primarily affects HTML pages, Axum's API-first architecture creates unique vulnerabilities.

The most common attack pattern involves embedding an Axum endpoint that performs state-changing operations. Consider an API endpoint that processes financial transactions:

async fn transfer_funds(
    Path((from_account, to_account, amount)): Path<(u64, u64, f64)>
) -> impl IntoResponse { 
    // Process transfer
    HttpResponse::Ok().finish()
}

A malicious site can embed this endpoint in an iframe with zero dimensions, overlaying invisible buttons on top of legitimate UI elements. When users believe they're clicking a "Submit" button on the attacker's page, they're actually triggering the Axum endpoint to transfer funds.

Another Axum-specific scenario involves WebSocket endpoints. Axum's WebSocket support allows real-time communication, but if authentication is handled solely through cookies without additional verification, clickjacking can lead to unauthorized WebSocket connections:

async fn websocket_endpoint(
    ws: WebSocket,
    data: web::Data<AppState>
) -> impl IntoResponse { 
    // WebSocket upgrade logic
}

Attackers can embed this endpoint and establish WebSocket connections under the victim's authenticated context, potentially accessing sensitive real-time data streams.

API endpoints that return sensitive data are also vulnerable. An endpoint that exposes user information without proper anti-clickjacking headers can be embedded to scrape data:

async fn get_user_data(
    Path(user_id): Path<u64>
) -> Result<Json<UserData>> { 
    // Return user data
}

The attacker's site can repeatedly embed this endpoint to harvest data from authenticated users who have active sessions with your Axum application.

Axum-Specific Detection

Detecting clickjacking vulnerabilities in Axum requires examining both your route definitions and response headers. The most reliable detection method is using middleBrick's API security scanner, which specifically tests for clickjacking vulnerabilities in Rust web applications.

middleBrick scans your Axum endpoints for missing X-Frame-Options headers and Content-Security-Policy frame-ancestors directives. The scanner sends requests to your API endpoints and analyzes the response headers to identify clickjacking vulnerabilities. Here's how to scan with middleBrick:

npx middlebrick scan https://your-axum-app.com/api/transfer 
# Or use the CLI tool
middlebrick scan https://your-axum-app.com/api/transfer

The scanner tests multiple attack scenarios: embedding endpoints in iframes, testing for cross-origin frame access, and verifying that sensitive endpoints cannot be framed. It provides a security score and specific findings about clickjacking vulnerabilities.

Manual detection involves checking your Axum route handlers for proper header configuration. Use middleware to inspect responses:

use axum::middleware::Next;
use axum::response::IntoResponse;
use axum::http::HeaderMap;

async fn clickjacking_middleware(
    mut req: axum::http::Request<axum::body::Body>,
    next: Next,
) -> impl IntoResponse { 
    let mut response = next.run(req).await;
    
    // Check if X-Frame-Options header exists
    if !response.headers().contains_key("x-frame-options") {
        // Vulnerability found - header missing
    }
    
    response
}

Run this middleware on your endpoints and verify that all responses include appropriate clickjacking protection headers. Pay special attention to endpoints that handle authentication, financial operations, or return sensitive data.

Axum-Specific Remediation

Remediating clickjacking vulnerabilities in Axum requires implementing proper HTTP headers and architectural safeguards. The most effective approach uses Axum's middleware system to enforce clickjacking protection across all endpoints.

First, implement the X-Frame-Options header using Axum middleware:

use axum::middleware::Next;
use axum::response::IntoResponse;
use axum::http::{HeaderMap, HeaderName, HeaderValue};

async fn clickjacking_protection(
    mut req: axum::http::Request<axum::body::Body>,
    next: Next,
) -> impl IntoResponse { 
    let mut response = next.run(req).await;
    
    // Add X-Frame-Options: DENY to prevent framing
    response.headers_mut().insert(
        "x-frame-options",
        HeaderValue::from_static("DENY")
    );
    
    response
}

let app = Router::new()
    .route("/api/transfer", post(transfer_funds))
    .layer(axum::middleware::from_fn(clickjacking_protection));

For more granular control, use Content-Security-Policy with frame-ancestors directive:

async fn csp_protection(
    mut req: axum::http::Request<axum::body::Body>,
    next: Next,
) -> impl IntoResponse { 
    let mut response = next.run(req).await;
    
    response.headers_mut().insert(
        "content-security-policy",
        HeaderValue::from_static("frame-ancestors 'none'")
    );
    
    response
}

For endpoints that legitimately need to be framed (like embedded widgets), use more specific policies:

response.headers_mut().insert(
    "content-security-policy",
    HeaderValue::from_static("frame-ancestors 'self' https://trusted.com")
);

Implement route-specific protection for sensitive operations:

async fn protected_transfer(
    Path((from_account, to_account, amount)): Path<(u64, u64, f64)>
) -> impl IntoResponse { 
    // Process transfer with additional anti-CSRF measures
    HttpResponse::Ok().finish()
}

let app = Router::new()
    .route("/api/transfer", post(protected_transfer))
    .layer(
        axum::middleware::from_fn(clickjacking_protection)
        .and_then(axum::middleware::from_fn(csp_protection))
    );

Combine clickjacking protection with CSRF tokens for maximum security. Axum's middleware chain allows stacking multiple security layers:

let security_middleware = clickjacking_protection
    .and_then(csp_protection)
    .and_then(csrf_protection);

let app = Router::new()
    .route(...)
    .layer(security_middleware);

Test your remediation using middleBrick to verify that clickjacking protections are properly implemented across all endpoints.

Frequently Asked Questions

How does clickjacking in Axum differ from traditional web applications?
Axum's API-first architecture means clickjacking often targets API endpoints rather than HTML pages. Attackers embed Axum endpoints that perform state-changing operations, exploiting the fact that many APIs rely on cookies for authentication without additional verification. The vulnerability manifests when malicious sites iframe your API endpoints to trick users into performing unintended actions like financial transfers or data exposure.
Can middleBrick detect clickjacking vulnerabilities in my Axum application?
Yes, middleBrick specifically scans Axum applications for clickjacking vulnerabilities. It tests your API endpoints for missing X-Frame-Options headers and Content-Security-Policy frame-ancestors directives. The scanner sends requests to your endpoints and analyzes response headers, providing a security score and detailed findings about clickjacking vulnerabilities. middleBrick's black-box scanning approach tests the actual runtime behavior of your Axum application without requiring source code access.