Clickjacking in Axum with Cockroachdb
Clickjacking in Axum with Cockroachdb — how this specific combination creates or exposes the vulnerability
Clickjacking is a client-side UI redress attack where an invisible or misleading layer tricks a user into interacting with a different page than intended. In an Axum application that uses Cockroachdb as the backend datastore, the vulnerability arises not from Cockroachdb itself, but from how HTTP responses are rendered and framed. If an Axum handler serves HTML or embeds API-driven content without explicit frame protection, an attacker can embed endpoints that query or mutate data in Cockroachdb via forged UI actions.
Consider an Axum route that renders a settings page after reading user preferences from Cockroachdb. If the response lacks X-Frame-Options or Content-Security-Policy (frame-ancestors), an attacker can place the page inside an <iframe> and overlay interactive elements. A user logged into the application might unknowingly submit a form or trigger a state-changing request that originates from a trusted origin but executes in the attacker’s context. Because Cockroachdb does not enforce per-request UI framing policies, the database layer cannot prevent this; the responsibility lies in the application’s HTTP layer.
In practice, this becomes critical when Axum endpoints return JSON that is rendered by a frontend framework and embedded by third parties. An attacker could craft a malicious page that loads an Axum endpoint returning sensitive Cockroachdb data (e.g., account balances or configuration) inside a hidden iframe, then use CSS to reposition elements to capture credentials or tokens. The OWASP API Top 10 lists broken object level authorization (BOLA) and security misconfiguration as relevant, and improper framing controls map to security misconfiguration when headers are missing.
With middleBrick, such misconfigurations are detectable because the scanner runs unauthenticated checks against the public API surface, including header analysis and client-side behavior probes. It does not fix the headers, but it provides findings with severity levels and remediation guidance so teams can address clickjacking risks before attackers exploit them.
Cockroachdb-Specific Remediation in Axum — concrete code fixes
To mitigate clickjacking in an Axum application backed by Cockroachdb, enforce framing controls at the HTTP response level. The following examples show how to set headers and construct safe responses.
1. Setting security headers in Axum
Use Axum middleware or response extensions to add X-Frame-Options and Content-Security-Policy. This prevents the browser from rendering responses in frames, regardless of how data is stored in Cockroachdb.
use axum::http::HeaderValue;
use axum::response::Response;
use std::convert::Infallible;
fn add_frame_protection(response: Response) -> Response {
let mut response = response;
// Prevent framing entirely
response.headers_mut().insert(
"X-Frame-Options",
HeaderValue::from_static("DENY"),
);
// Explicitly allow no embedding by any ancestor
response.headers_mut().insert(
"Content-Security-Policy",
HeaderValue::from_static("frame-ancestors 'none'"),
);
response
}
// Apply as a layer or per-route
let app = Router::new()
.route("/settings", get(settings_handler))
.layer(axum::middleware::from_fn(|req, next| {
let fut = next.run(req);
async { Ok::<_, Infallible>(add_frame_protection(fut.await?)) }
}));
2. Example Cockroachdb query in Axum handler
Ensure that responses are framed safely when data is retrieved from Cockroachdb. The handler should not embed sensitive logic inside frames, and it should set headers before returning the response.
use axum::extract::State;
use cockroachdb_csi::proto::cockroach::kvnemesis::Timestamp;
use sqlx::postgres::PgPoolOptions;
use sqlx::PgPool;
struct AppState {
pool: PgPool,
}
async fn settings_handler(
State(state): State,
) -> Response {
let user_id = /* obtain user_id from session or JWT */;
let row = state.pool
.query_one(
"SELECT theme, notifications_enabled FROM user_prefs WHERE user_id = $1",
&[&user_id],
)
.await
.expect("Failed to fetch prefs");
let theme: String = row.get(0);
let notifications: bool = row.get(1);
let html = format!(r#"
<!doctype html>
<html>
<head>
<meta http-equiv="Content-Security-Policy" content="frame-ancestors 'none'">
<meta http-equiv="X-Frame-Options" content="DENY">
</head>
<body>
<h1>Settings</h1>
<p>Theme: {theme}</p>
<p>Notifications: {notifications}</p>
</body>
</html>
"#);
Response::builder()
.header("X-Frame-Options", "DENY")
.header("Content-Security-Policy", "frame-ancestors 'none'")
.body(html.into_bytes())
.unwrap()
}
3. Middleware approach for global enforcement
For larger applications, apply framing headers via middleware so every route benefits, including those that query Cockroachdb. This complements database-level security by ensuring the transport and presentation layers remain secure.
use axum::async_trait;
use axum::http::Request;
use axum::middleware::Next;
use axum::response::Response;
struct FrameProtection;
#[axum::async_trait]
impl axum::middleware::Layer for FrameProtection {
type Service = FrameProtectionService;
fn layer(&self, inner: S) -> Self::Service {
FrameProtectionService { inner }
}
}
struct FrameProtectionService {
inner: S,
}
#[axum::async_trait]
impl axum::middleware::Next for FrameProtectionService
where
S: axum::extract::FromRequest + Send,
S::Rejection: Into,
B: Send + 'static,
{
async fn run(
&mut self,
req: Request<B>,
next: Next<S, B>
) -> Result {
let mut res = next.run(req).await;
res.headers_mut().insert(
"X-Frame-Options",
HeaderValue::from_static("DENY"),
);
res.headers_mut().insert(
"Content-Security-Policy",
HeaderValue::from_static("frame-ancestors 'none'"),
);
Ok(res)
}
}
By combining these patterns, an Axum service backed by Cockroachdb reduces the attack surface for clickjacking. MiddleBrick can validate the presence of these headers during scans, providing actionable findings when protections are absent.