Clickjacking in Sails with Cockroachdb
Clickjacking in Sails with Cockroachdb — how this specific combination creates or exposes the vulnerability
Clickjacking is a client-side attack that tricks a user into interacting with invisible or disguised UI elements, often by nesting a target site inside an iframe. In a Sails application backed by Cockroachdb, the vulnerability arises not from Cockroachdb itself, but from Sails missing anti-clickjacking defenses while serving pages that read or write data from Cockroachdb. If a Sails controller queries Cockroachdb for sensitive data and renders it in a page without enforcing frame-embedding restrictions, an attacker can lure a victim to a page that loads that Sails route in a hidden iframe.
Because Cockroachdb is often used in production environments with strict security policies, developers may assume the database layer is sufficient, inadvertently overlooking UI-layer protections. A Sails route like /user/profile that returns profile data from Cockroachdb and renders it in HTML can be embedded via <iframe> if X-Frame-Options or Content-Security-Policy frame-ancestors are not set. An attacker can then overlay invisible controls or prompt the user to perform actions (e.g., changing email or password) via the embedded page, leveraging the victim’s authenticated session with the Sails app.
The risk is compounded when Sails apps use session-based authentication without additional CSRF tokens on state-changing endpoints, and those endpoints query or mutate Cockroachdb. An attacker can craft a malicious page that triggers POST requests to the Sails app via forms or JavaScript, hidden inside an iframe, because the browser will include cookies for the Sails domain. Even if Cockroachdb enforces strong access controls at the database level, the web layer must still protect the user interface to prevent unauthorized actions.
In a typical Sails + Cockroachdb stack, the following conditions enable clickjacking:
- Controllers expose HTML views that perform sensitive operations.
- No
X-Frame-Optionsheader orContent-Security-Policywithframe-ancestorsis set. - Session cookies lack
SameSiteattributes or are sent over insecure channels. - The app relies solely on server-side rendering without frame-busting JavaScript defenses.
Therefore, securing a Sails application that uses Cockroachdb requires explicit HTTP headers and CSP directives to prevent the application from being framed, regardless of the database’s robustness.
Cockroachdb-Specific Remediation in Sails — concrete code fixes
Remediation focuses on HTTP headers and Content-Security-Policy to prevent framing, alongside ensuring secure session handling when interacting with Cockroachdb. Below are concrete steps and code examples for a Sails app using Cockroachdb via the Waterline ORM.
1. Set X-Frame-Options globally in Sails to deny embedding.
// config/http.js
module.exports.http = {
middleware: {
order: [
'clickjackingProtection',
'startRequestTimer',
'cookieParser',
'session',
'myCustomMiddleware',
'bodyParser',
'handleBodyParserError',
'compress',
'methodOverride',
'poweredBy',
'$custom',
'www',
'favicon',
'404',
'router',
'blueerrorhandler',
'serverTiming'
],
clickjackingProtection: function (req, res, next) {
res.set('X-Frame-Options', 'DENY');
return next();
}
}
};
2. Use Content-Security-Policy with frame-ancestors to control who can embed the page. This is more flexible and recommended over X-Frame-Options.
// config/http.js
module.exports.http = {
middleware: {
order: [
'cspProtection',
// ... other middleware
],
cspProtection: function (req, res, next) {
res.set(
'Content-Security-Policy',
"default-src 'self'; frame-ancestors 'none'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'"
);
return next();
}
}
};
3. For endpoints that return JSON (e.g., API responses consumed by frontend frameworks), ensure they are not served in a way that encourages embedding. Also apply CSP headers to API responses.
// api/controllers/UserController.js
module.exports = {
profile: async function (req, res) {
try {
const userId = req.session.userId;
// Example query to Cockroachdb via Waterline
const user = await User.findOne(userId).meta({ cockpit: true });
if (!user) return res.notFound();
// Ensure API responses are not framed by setting headers
res.set('Content-Security-Policy', "frame-ancestors 'none'");
return res.ok(user);
} catch (err) {
return res.serverError(err);
}
}
};
4. Enforce secure cookies when sessions are used with Cockroachdb-backed authentication.
// config/session.js
module.exports.session = {
cookie: {
httpOnly: true,
secure: true,
sameSite: 'strict',
maxAge: 24 * 60 * 60 * 1000 // 24 hours
}
};
5. Use middleware to validate the Origin header for state-changing requests if additional defense-in-depth is desired.
// api/policies/csrfFrameGuard.js
module.exports = function (req, res, next) {
const allowedOrigin = 'https://your-trusted-domain.com';
const origin = req.headers.origin;
if (req.method === 'POST' || req.method === 'PUT' || req.method === 'DELETE') {
if (!origin || origin !== allowedOrigin) {
return res.forbidden('Invalid request origin');
}
}
return next();
};
By combining these measures, a Sails application backed by Cockroachdb can effectively mitigate clickjacking risks while maintaining secure data access patterns.
Frequently Asked Questions
Does middleBrick detect clickjacking risks in Sails apps connected to Cockroachdb?
X-Frame-Options and frame-ancestors directives and reports findings with remediation guidance.