Clickjacking in Rocket with Bearer Tokens
Clickjacking in Rocket with Bearer Tokens — how this specific combination creates or exposes the vulnerability
Clickjacking is a client-side vulnerability where an attacker tricks a user into interacting with a hidden or disguised UI element inside an iframe. When Bearer Tokens are used for authentication in Rocket, a clickjacking-prone page can expose those tokens if the application embeds authenticated endpoints in iframes or fails to enforce frame-ancestor policies. Rocket is a web framework that encourages explicit route handling; however, if developers render authenticated views inside frames without setting appropriate CSP headers, a forged page can load those routes and capture actions or tokens leaked via side-channels such as reflected headers or cookies.
In this context, a Bearer Token is typically sent in the Authorization header (e.g., Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...). Even though the token itself is not directly accessible across origins due to same-origin policies and CORS, clickjacking can bypass user consent for actions that the authenticated user is authorized to perform. For example, an attacker may embed an authenticated Rocket endpoint that performs state-changing operations (like changing email or password) inside an invisible iframe and overlay interactive elements to induce clicks. If the application relies solely on the presence of a Bearer Token in headers for authorization and does not validate the Origin header or use anti-CSRF tokens for state-changing requests, the attack may succeed in performing unauthorized operations while appearing to come from the victim’s session.
Moreover, if Rocket APIs return sensitive data in responses and those endpoints are embeddable via iframe, an attacker can use CSS tricks to read reflected content or induce requests that reveal information. Although Bearer Tokens are not stored in local storage by the framework itself, client-side code may inadvertently expose them via JavaScript errors, referer headers, or logging when embedded in third-party frames. The combination of clickjacking techniques and Bearer Token-based authentication in Rocket becomes critical when the application does not implement frame-ancestor restrictions, lacks proper X-Frame-Options or Content-Security-Policy frame-ancestors directives, and does not validate the request origin for sensitive operations.
Consider an endpoint defined in Rocket that updates user settings and expects a Bearer Token in the Authorization header. If this route is inadvertently accessible via an embedded iframe and does not verify the Origin header, an attacker can craft a page that loads the endpoint in a hidden form, triggering a request with the user’s credentials. While Rocket’s guards and request guards help ensure authentication, they do not automatically protect against UI redressing unless the developer explicitly adds protections at the HTTP response level. Therefore, securing against clickjacking in Rocket with Bearer Tokens requires a defense-in-depth approach that combines frame-ancestor policies, anti-CSRF practices, and careful handling of authenticated routes exposed to browser embedding contexts.
Bearer Tokens-Specific Remediation in Rocket — concrete code fixes
Remediation focuses on preventing unauthorized embedding of authenticated endpoints and ensuring that requests with Bearer Tokens originate from trusted contexts. In Rocket, you can set HTTP headers to mitigate clickjacking and strengthen token handling. Below are concrete code examples that demonstrate how to configure your Rocket routes and guards to reduce risk.
1. Set Content-Security-Policy frame-ancestors
Prevent your authenticated pages from being embedded in iframes by adding a CSP header that restricts frame ancestors. This is effective across modern browsers and complements other defenses.
// In main.rs or a fairing
use rocket::http::Header;
use rocket::response::Response;
#[rocket::async_trait]
impl<'r> rocket::request::FromRequest<'r> for MyAuthGuard {
type Error = ();
async fn from_request(req: &'r Request<'_>) -> request::Outcome {
// Your token validation logic
}
}
#[get("/settings")]
async fn settings() -> &'static str {
"Secure settings"
}
#[rocket::main]
async fn main() {
rocket::build()
.attach(rocket_cors::CorsFairing::new(|cors| {
cors.set_allowed_origins(vec!["https://trusted.example.com"]);
}))
.mount("/", routes![settings])
.launch()
.await;
}
To set CSP directly, you can add a response guard that injects the header for sensitive routes:
use rocket::response::Responder;
use rocket::{Request, Response};
pub struct SecurityHeaders;
#[rocket::async_trait]
impl<'r> rocket::response::Responder<'r, 'static> for SecurityHeaders {
fn respond_to(self, req: &Request) -> rocket::response::Result<'static> {
let mut response = Response::build();
response.set_header(rocket::http::Header::new(
"Content-Security-Policy",
"frame-ancestors 'self' https://trusted.example.com",
));
response.set_header(rocket::http::Header::new(
"X-Frame-Options",
"DENY",
));
Ok(response)
}
}
2. Validate Origin and Referer for state-changing routes
For endpoints that modify state and accept Bearer Tokens, validate the Origin header to ensure requests come from your domain. This helps block cross-origin requests that could be induced via clickjacking.
use rocket::request::{Request, Outcome};
use rocket::http::Status;
fn validate_origin(req: &Request) -> bool {
if let Some(origin) = req.headers().get_one("Origin") {
origin == "https://your-app.com"
} else if let Some(referer) = req.headers().get_one("Referer") {
// Basic check; consider using a crate for URL parsing
referer.starts_with("https://your-app.com")
} else {
false
}
}
#[post("/update", data = &)
async fn update(body: String, req: &Request) -> Result {
if !validate_origin(req) {
return Err(Status::Forbidden);
}
// Process update with Bearer Token in Authorization header
Ok("Updated".into())
}
3. Use anti-CSRF tokens for sensitive actions
Even with Bearer Tokens, adding anti-CSRF tokens for state-changing operations provides an additional layer of protection. Store a token in a secure, HttpOnly cookie and require it in headers or form fields.
use rocket::State;
use rocket::form::Form;
struct CsrfToken(String);
#[rocket::async_trait]
impl<'r> rocket::request::FromRequest<'r> for CsrfToken {
type Error = ();
async fn from_request(req: &'r Request<'_>) -> Outcome {
// Validate token from header or form against session store
Outcome::Success(CsrfToken("valid-token".into()))
}
}
#[post("/action", data = &input)]
async fn perform_action(csrf: CsrfToken, input: Form) -> String {
// Proceed with action
"Action performed".into()
}
Combine these measures: set strict CSP and X-Frame-Options, validate Origin/Referer for sensitive endpoints, and use anti-CSRF tokens for state-changing operations. This reduces the attack surface for clickjacking against routes that rely on Bearer Tokens in Rocket applications.