Clickjacking in Hapi with Cockroachdb
Clickjacking in Hapi with Cockroachdb — how this specific combination creates or exposes the vulnerability
Clickjacking is a client-side interface manipulation attack where an attacker tricks a user into interacting with invisible or disguised UI elements. In a Hapi application backed by Cockroachdb, the vulnerability typically arises not from Cockroachdb itself, but from missing HTTP response headers and insecure UI composition that allow malicious sites to embed your routes in an <iframe>. Because Cockroachdb is often used as a distributed SQL backend for user data and session state, an authenticated user’s sensitive actions—such as changing email, updating permissions, or transferring funds—can be triggered via forged UI overlays if the application does not enforce frame-embedding restrictions.
With Hapi, routes that render HTML (e.g., via a view engine like Handlebars or React SSR) must explicitly set Content-Security-Policy frame-ancestors and X-Frame-Options to prevent embedding. If these headers are omitted or set too broadly (e.g., frame-ancestors ‘self’ missing or using ALLOW-FROM which is obsolete), an attacker can craft a page that embeds your dashboard or admin routes. Because Cockroachdb handles the persistence layer, compromised UI interactions can lead to unauthorized database writes via authenticated requests initiated through the embedded interface.
Consider a Hapi route that performs a state-changing POST to /account/change-email. If this route relies on session cookies for authentication and does not enforce anti-CSRF tokens or SameSite cookies, an attacker can lure a logged-in user to a page with a transparent iframe pointing to that endpoint. Cockroachdb will still process the request if the session is valid, resulting in an unintended email change. MiddleBrick’s scans detect missing frame-ancestors and weak CSP directives across the unauthenticated attack surface, highlighting these classes of misconfiguration even when Cockroachdb is the backend datastore.
To validate exposure, security checks examine response headers and CSP directives returned by Hapi for routes that render forms or perform mutations. Absence of a strict Content-Security-Policy with frame-ancestors ‘none’ or a restrictive set, combined with missing X-Frame-Options, signals a detectable misconfiguration. Note that MiddleBrick detects and reports these issues with remediation guidance but does not modify headers or enforce policies; you must implement the fixes in your Hapi server and application code.
Cockroachdb-Specific Remediation in Hapi — concrete code fixes
Remediation centers on HTTP headers and secure UI practices in Hapi, while ensuring Cockroachdb-backed routes remain robust. Below are concrete, working examples that you can adapt to your project.
1. Enforce CSP and X-Frame-Options in Hapi
Register a server extension or use a dedicated strategy to inject security headers on every response. This ensures that pages backed by Cockroachdb cannot be framed.
const Hapi = require('@hapi/hapi');
const security = require('hapi-security-headers'); // community helper; implement if preferred
const init = async () => {
const server = Hapi.server({ port: 4000, host: 'localhost' });
server.ext('onPreResponse', (request, h) => {
const response = request.response;
if (response.variety === 'view' || response.variety === 'plain') {
response.header('Content-Security-Policy', "default-src 'self'; frame-ancestors 'none'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'");
response.header('X-Frame-Options', 'DENY');
}
return h.continue;
});
server.route({
method: 'GET',
path: '/dashboard',
handler: (request, h) => h.view('dashboard', { user: request.auth.credentials })
});
await server.start();
};
init();
2. Use anti-CSRF tokens and SameSite cookies for Cockroachdb-backed mutations
Even with frame restrictions, state-changing endpoints should validate CSRF tokens and enforce SameSite cookies. Below is a minimal Hapi route that demonstrates secure form handling backed by Cockroachdb using the pg client.
const Hapi = require('@hapi/hapi');
const { Pool } = require('pg');
const crypto = require('crypto');
const pool = new Pool({
connectionString: 'postgresql://user:password@host:26257/dbname?sslmode=require'
});
const generateToken = () => crypto.randomBytes(32).toString('hex');
const init = async () => {
const server = Hapi.server({ port: 4000, host: 'localhost' });
server.state('session', {
ttl: 24 * 60 * 60 * 1000,
isSecure: true,
isHttpOnly: true,
path: '/',
strictHeader: true,
encoding: 'base64json',
clearInvalid: true
});
server.route([
{
method: 'GET',
path: '/change-email',
handler: (request, h) => {
const csrfToken = generateToken();
request.cookieAuth.set({ csrfToken });
return h.view('change-email', { csrfToken });
}
},
{
method: 'POST',
path: '/change-email',
options: {
validate: {
payload: (value, helpers) => {
const { email, csrfToken } = value;
if (!csrfToken || csrfToken !== request.cookieAuth.get('csrfToken')) {
return helpers.error('any.invalid');
}
return value;
}
}
},
handler: async (request, h) => {
const { email } = request.payload;
const csrfToken = request.payload.csrfToken;
if (!csrfToken || csrfToken !== request.cookieAuth.get('csrfToken')) {
return h.response('Invalid CSRF').code(403);
}
await pool.query('UPDATE users SET email = $1 WHERE id = $2', [email, request.auth.credentials.userId]);
return h.redirect('/dashboard');
}
}
]);
await server.start();
};
init();
3. MiddleBrick integration
Use the CLI to verify that headers and CSP are correctly enforced after changes:
middlebrick scan https://your-hapi-app.example.com/dashboard
With the Pro plan, enable continuous monitoring so that future regressions in header policies are flagged automatically. The GitHub Action can fail builds if risk scores drop below your chosen threshold, and the MCP Server lets you scan APIs directly from your AI coding assistant while iterating on Hapi routes backed by Cockroachdb.