Clickjacking in Firestore
How Clickjacking Manifests in Firestore
Clickjacking in Firestore environments typically exploits the platform's client-side SDK and web integration patterns. When Firestore is used in web applications, developers often embed interactive UI components that directly manipulate database state. These components create attack surfaces that malicious actors can exploit through iframed interfaces.
The most common Firestore clickjacking pattern involves overlaying transparent iframes containing Firestore-powered applications. Attackers position clickable elements to coincide with legitimate UI components. When victims believe they're interacting with their own application, they're actually triggering database operations within the attacker's controlled context.
Firestore's real-time capabilities make this particularly dangerous. The SDK's onSnapshot listeners and addDoc operations can be triggered without obvious user feedback. An attacker might overlay a "Delete All Data" button on top of a seemingly innocuous "Refresh" button, causing users to unknowingly wipe their Firestore collections.
Consider this vulnerable pattern:
// Vulnerable Firestore component
const db = getFirestore();
// Direct database operations exposed in UI
const deleteCollection = async (collectionId) => {
const query = collection(collectionId, db);
const docs = await getDocs(query);
docs.forEach(doc => deleteDoc(doc.ref));
};
// UI button that could be clickjacked
<button onclick="deleteCollection('users')">Delete All Users</button>Without proper framing protections, this button could be overlayed on top of legitimate UI elements. The attack becomes even more potent when combined with Firestore's security rules. If rules allow unauthenticated writes or have overly permissive conditions, clickjacking can bypass what developers assume is secure access control.
Another Firestore-specific variant involves the addDoc operation for creating new documents. Attackers can craft iframes that trigger document creation with malicious field values, potentially escalating privileges or injecting harmful data into collections that other parts of the application trust implicitly.
Firestore's offline persistence feature adds another layer of complexity. When applications enable enablePersistence, local data modifications can be queued and synchronized later. Clickjacking attacks during offline periods might result in unexpected data states when the device reconnects, making detection and debugging significantly harder.
The authentication state management in Firestore also presents clickjacking opportunities. If an application maintains Firestore sessions without proper frame-busting code, attackers can create iframes that appear to be the legitimate application but operate with the victim's authenticated context, potentially performing actions the user didn't intend.
Firestore-Specific Detection
Detecting clickjacking vulnerabilities in Firestore applications requires a multi-layered approach. The first line of defense is verifying proper frame-busting implementations across all web-facing components that interact with Firestore.
Manual detection involves testing whether your application can be successfully iframed. Open your application URL in an iframe on a different domain and attempt to interact with Firestore-powered features. If operations succeed, you have a clickjacking vulnerability. Tools like iframe-resizer can help test these scenarios systematically.
For automated detection, middleBrick's security scanner specifically tests for clickjacking vulnerabilities in Firestore contexts. The scanner attempts to load your application in an iframe and verifies whether frame-busting headers and JavaScript protections are properly implemented. It checks for:
- X-Frame-Options header presence and correct values
- Content-Security-Policy frame-ancestors directives
- JavaScript frame-busting implementations
- Firestore SDK initialization patterns that might be vulnerable
The scanner also analyzes your Firestore security rules for overly permissive write operations that could be exploited through clickjacking. It looks for patterns like allow write: if true; or rules that don't properly validate document ownership before allowing modifications.
Code analysis tools can detect vulnerable patterns in your Firestore integration. Look for these red flags in your codebase:
// Vulnerable: no frame protection
const db = getFirestore();
const deleteDocBtn = document.getElementById('delete-doc');
deleteDocBtn.addEventListener('click', () => {
deleteDoc(docRef); // Could be triggered via clickjacking
});Network analysis during testing can reveal whether Firestore operations can be triggered from iframed contexts. Use browser developer tools to monitor requests when your application is loaded in an iframe, looking for successful database operations that should be blocked.
middleBrick's scanner provides specific findings for Firestore clickjacking, including severity assessments based on the sensitivity of data exposed and the strength of existing protections. The tool generates reports that map directly to OWASP API Security Top 10 categories, helping you prioritize remediation efforts.
Firestore-Specific Remediation
Securing Firestore applications against clickjacking requires implementing multiple defensive layers. The most fundamental protection is proper frame-busting at the HTTP header level using Content-Security-Policy.
Implement this CSP header to prevent your application from being framed by unauthorized sources:
Content-Security-Policy: frame-ancestors 'none'For applications that legitimately need to be framed (like embedded dashboards), specify exact allowed origins:
Content-Security-Policy: frame-ancestors https://yourdomain.comComplement CSP with X-Frame-Options as a fallback for older browsers:
X-Frame-Options: DENYOn the client side, implement JavaScript frame-busting as an additional layer:
// Frame-busting protection
if (window.location !== window.parent.location) {
window.top.location = window.location;
}
// More robust implementation
const frameBusting = () => {
try {
if (window.self !== window.top) {
window.top.location = window.self.location;
}
} catch (e) {
// In case of cross-origin restrictions
window.top.location = window.self.location;
}
};
// Execute on page load
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', frameBusting);
} else {
frameBusting();
}Firestore-specific security rules should enforce proper authentication and authorization regardless of how operations are triggered:
Implement UI safeguards that make clickjacking attacks more difficult to execute successfully. Add confirmation dialogs for destructive operations:
const safeDelete = async (collectionId) => {
const confirmed = confirm('Are you sure you want to delete this collection?');
if (!confirmed) return;
// Add additional verification
const verificationCode = prompt('Enter verification code:');
if (verificationCode !== 'DELETE_CONFIRM') return;
// Proceed with deletion
const query = collection(collectionId, db);
const docs = await getDocs(query);
docs.forEach(doc => deleteDoc(doc.ref));
};For applications using Firestore with React or similar frameworks, implement component-level protections:
const SecureFirestoreComponent = () => {
const [isFramed, setIsFramed] = useState(false);
useEffect(() => {
setIsFramed(window.location !== window.parent.location);
}, []);
if (isFramed) {
return (
<div style={{ padding: '20px', backgroundColor: '#f8f9fa' }}>
<p>This application cannot be used in a framed context for security reasons.</p>
</div>
);
}
return (
<div>
<h1>Secure Firestore Application</h1>
<FirestoreOperations />
</div>
);
};Finally, implement comprehensive logging and monitoring for Firestore operations. Track the origin of requests and flag unusual patterns that might indicate clickjacking attacks:
const secureFirestoreOperation = async (operation, data) => {
const operationLog = {
userId: getAuth().currentUser.uid,
operationType: operation,
data: data,
timestamp: serverTimestamp(),
userAgent: navigator.userAgent,
referrer: document.referrer,
isFramed: window.location !== window.parent.location
};
// Log suspicious activity
if (operationLog.isFramed) {
console.warn('Firestore operation attempted from framed context', operationLog);
// Optionally block or require additional verification
}
// Proceed with operation if authorized
return await firestoreOperation(operation, data);
};