Clickjacking in Spring Boot with Firestore
Clickjacking in Spring Boot with Firestore — how this specific combination creates or exposes the vulnerability
Clickjacking is a client-side interface manipulation attack where an attacker tricks a user into clicking or interacting with a hidden or disguised UI element. When a Spring Boot application integrates with Google Cloud Firestore and renders views (for example using Thymeleaf or JSP), misconfigured HTTP headers or insufficient frame controls can allow an attacker to embed the Firestore-backed UI inside an invisible iframe. Because the browser will send credentials and session cookies to your domain when loading the embedded page, the attacker can hijack actions such as reading or writing Firestore documents on behalf of the authenticated user.
In this combination, the risk is amplified when Spring Boot endpoints serve pages that perform Firestore operations (reads/writes) without verifying that the request originates from a trusted frame context. If your app exposes an endpoint like /firestore/update-profile that accepts POST requests and performs Firestore writes based on user session data, an attacker can craft a malicious page that loads this endpoint in a hidden iframe and triggers the action via a disguised button or link. Because the browser automatically includes cookies (including session identifiers), the server-side Spring Boot logic may trust the request and execute the Firestore operation, assuming it is intentional. The Firestore security rules themselves do not protect against this because the request is authenticated and authorized at the application layer, not at the UI layer.
Additionally, if your Spring Boot app embeds third-party content or exposes admin/debug pages that interact with Firestore, those pages can be framed by external sites. Without explicit frame-ancestor restrictions, an attacker can use social engineering to lure a victim to a page that performs sensitive Firestore operations (such as updating permissions or writing data). The browser’s same-origin policy does not prevent framing, so the attack relies on missing or weak Content Security Policy (CSP) frame-ancestors and the absence of anti-clickjacking headers like X-Frame-Options or Content-Security-Policy with strict framing rules.
Firestore-Specific Remediation in Spring Boot — concrete code fixes
Remediation focuses on preventing your pages and endpoints from being embedded in untrusted frames and ensuring that Firestore operations are protected by strict origin checks. Implement HTTP response headers and CSP policies in your Spring Boot application, and design your Firestore interactions to validate the request origin when necessary.
1. Set X-Frame-Options and Content-Security-Policy headers
Configure your Spring Boot application to send anti-clickjacking headers for all responses that render UI or invoke Firestore operations. In a Spring Boot web app, you can add a filter or use an MVC interceptor.
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class SecurityHeadersFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletResponse res = (HttpServletResponse) response;
// Prevent framing entirely
res.setHeader("X-Frame-Options", "DENY");
// Alternatively, allow framing only from same origin:
// res.setHeader("Content-Security-Policy", "frame-ancestors 'self'");
chain.doFilter(request, response);
}
}
Register the filter in your Spring Boot configuration:
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class FilterConfig {
@Bean
public FilterRegistrationBean<SecurityHeadersFilter> securityHeadersFilter() {
FilterRegistrationBean<SecurityHeadersFilter> registration = new FilterRegistrationBean<>();
registration.setFilter(new SecurityHeadersFilter());
registration.addUrlPatterns("/*");
return registration;
}
}
2. Validate Origin for sensitive Firestore operations
If your endpoints must be embeddable (e.g., for widgets), use Content-Security-Policy frame-ancestors to restrict sources and validate the Origin or Referer header on the server side before performing Firestore writes.
import com.google.cloud.firestore.Firestore;
import com.google.cloud.firestore.FirestoreOptions;
import javax.servlet.http.HttpServletRequest;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class FirestoreController {
private final Firestore db = FirestoreOptions.getDefaultInstance().getService();
@PostMapping("/firestore/update-profile")
public String updateProfile(@RequestBody ProfileUpdate payload, HttpServletRequest request) {
String origin = request.getHeader("Origin");
String referer = request.getHeader("Referer");
// Basic origin validation — adapt to your trusted origins
if (origin == null && referer == null) {
throw new SecurityException("Invalid request origin");
}
// Ensure origin matches expected domain
if (origin != null && !origin.equals("https://your-trusted-app.com")) {
throw new SecurityException("Invalid request origin");
}
// Proceed with Firestore update
db.collection("profiles").document(payload.getUserId())
.set(payload.getData())
.join();
return "OK";
}
}
3. Use CSP frame-ancestors in your pages
When serving HTML/JS that interacts with Firestore, include a strong CSP header to restrict which sites can frame your content. In development or hybrid apps, avoid frame-ancestors 'unsafe-inline' or wildcard policies.
res.setHeader("Content-Security-Policy", "default-src 'self'; frame-ancestors 'self';");
This prevents browsers from rendering your Firestore-backed UI inside an attacker-controlled iframe, mitigating clickjacking. Combine this with proper session management and ensure that Firestore security rules enforce authentication and least-privilege access for each document operation.