Clickjacking in Sails with Firestore
Clickjacking in Sails with Firestore — how this specific combination creates or exposes the vulnerability
Clickjacking is a client-side UI redress attack where an attacker tricks a user into clicking or interacting with a transparent or disguised element inside an embedded frame. In a Sails application that uses Cloud Firestore as a backend, the risk arises when views render dynamic data without enforcing frame-busting or Content Security Policy (CSP) rules, and when Firestore data is exposed via endpoints that do not validate the request origin.
Sails does not set anti-clickjacking headers by default. If a controller action streams Firestore documents to a view using a client-side embed (e.g., an iframe) or renders a page that includes external widgets, an attacker can host a malicious page that overlays invisible controls on top of authenticated UI elements. Because Firestore security rules typically enforce read/write at the document level and do not inherently consider the embedding context, a compromised UI can trigger unintended Firestore reads or writes via forged requests initiated from the embedded context.
Consider a Sails route that exposes a Firestore document by ID without verifying the request’s referer or origin. An attacker can load this route inside an iframe, hide it, and simulate clicks by positioning interactive elements (buttons, links) over the iframe. If the page contains logic that directly uses Firestore client-side SDK with user credentials, a signed-in user may inadvertently invoke operations (e.g., updating permissions or triggering Cloud Functions) that appear to be benign navigation.
Because middleBrick tests unauthenticated attack surfaces and checks Security Misconfiguration and Input Validation across 12 parallel checks, it can surface exposed endpoints that may contribute to clickjacking risk when combined with UI embedding issues. For example, a misconfigured CORS or missing X-Frame-Options header may be flagged alongside overly permissive Firestore rules that allow read access based only on document ID without considering request origin.
In a real assessment, middleBrick’s OpenAPI/Swagger analysis resolves $ref definitions and cross-references runtime behavior with spec definitions, which can highlight routes that return sensitive Firestore data without framing protections. This does not constitute a fix, but it provides findings with severity and remediation guidance to help developers address the UI and server-side configuration that together enable clickjacking in a Firestore-integrated Sails app.
Firestore-Specific Remediation in Sails — concrete code fixes
Remediation focuses on two layers: server-side HTTP headers and client-side UI controls, while keeping Firestore security rules intact. In Sails, you can set CSP and anti-frame headers in policies or hooks, and adjust frontend templates to prevent embedding attacks.
1. Set anti-clickjacking headers via a policy
Create a policy that adds X-Frame-Options and Content-Security-Policy frame-ancestors rules. Apply this policy to routes that render views or serve API responses consumed by browsers.
// api/policies/csp-frame.js
module.exports = function cspFrame(req, res, next) {
res.set('X-Frame-Options', 'DENY');
res.set('Content-Security-Policy', "frame-ancestors 'none'");
return next();
};
Then register the policy in config/policies.js and attach it to relevant controllers or actions.
2. Tighten Firestore read rules by request origin
Firestore security rules cannot inspect HTTP referers directly, so move origin validation to your Sails backend. Create an endpoint that checks the request origin and conditionally returns document references or tokens needed by the client-side SDK.
// api/controllers/FirestoreController.js
const { initializeApp } = require('firebase-admin/app');
const { getFirestore } = require('firebase-admin/firestore');
module.exports = {
getDocument: async function(req, res) {
const allowedOrigin = process.env.ALLOWED_ORIGIN || 'https://yourdomain.com';
const requestOrigin = req.headers.origin || req.headers.referer || '';
if (!requestOrigin.startsWith(allowedOrigin)) {
return res.forbidden({ error: 'Invalid origin' });
}
initializeApp();
const db = getFirestore();
const doc = await db.collection('items').doc(req.param('id')).get();
if (!doc.exists) {
return res.notFound();
}
return res.ok(doc.data());
}
};
This ensures that only requests with an expected origin can retrieve Firestore data, reducing the attack surface for clickjacking-induced reads.
3. Avoid embedding sensitive UI in iframes
In your Sails views (e.g., EJS), avoid rendering pages inside iframes when they rely on authenticated Firestore access. If embedding is required, use CSP frame-ancestors to restrict parents and add sandbox attributes with strict allowlist.
<!-- views/page.ejs -->
<iframe src="/internal/widget" sandbox="allow-scripts allow-same-origin"></iframe>
Combine this with the CSP policy above to enforce that the page cannot be embedded by external sites.
4. Use CSRF tokens for state-changing operations
Even with headers and origin checks, ensure that mutating Firestore writes require CSRF protection. Sails has built-in CSRF protection for views; ensure it is enabled and applied to forms that trigger Firestore updates via the backend.
<!-- In a form -->
<input type="hidden" name="_csrf" value="<%= _csrf %>">
This prevents unauthorized commands from being executed when a user is tricked into interacting with a disguised UI element.
5. Validate and sanitize all inputs
Use Sails’ built-in validation and sanitizers to ensure that Firestore document IDs and query parameters are strictly formatted, preventing injection-style UI abuse that could be leveraged alongside clickjacking vectors.