PrepZone Logo
PrepZone

CORS, CSRF, and Production Checklist

Browser security, CSRF protection and the checklist before you deploy.

Why this matters

  • Misconfigured CORS blocks legitimate frontend clients or accidentally allows any origin to call your API.
  • CSRF attacks trick authenticated users into performing unwanted actions — dangerous for cookie-based sessions.
  • A pre-deployment checklist catches the security gaps that code review misses.
CorsFilter
JwtAuthFilter
AuthorizationFilter
Controller
Each filter handles one concern. Order matters — authentication before authorization.

CORS configuration

When the BookStore React frontend (https://app.bookstore.example.com) calls the API (https://api.bookstore.example.com), the browser enforces CORS:

Java
@Configuration
public class CorsConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/api/**")
            .allowedOrigins("https://app.bookstore.example.com")
            .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
            .allowedHeaders("Authorization", "Content-Type", "X-Correlation-Id")
            .exposedHeaders("X-Correlation-Id")
            .maxAge(3600);
    }
}

Or via Spring Security:

Java
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http.cors(cors -> cors.configurationSource(request -> {
        CorsConfiguration config = new CorsConfiguration();
        config.setAllowedOrigins(List.of("https://app.bookstore.example.com"));
        config.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE"));
        config.setAllowedHeaders(List.of("Authorization", "Content-Type"));
        return config;
    }));
    // ... authorization rules
    return http.build();
}

CORS rules for BookStore

  • allowedOrigins — Explicit origin list. Never use * with credentials.
  • allowedMethods — HTTP verbs the frontend may use.
  • allowedHeaders — Request headers the frontend may send.
  • exposedHeaders — Response headers the frontend JavaScript can read.
  • maxAge — How long the browser caches preflight results.

CSRF protection

CSRF exploits cookie-based sessions: a malicious site submits a form to your API using the victim's session cookie.

For stateless JWT APIs: disable CSRF — tokens in headers are not sent automatically by browsers.

Java
http.csrf(csrf -> csrf.disable());

For cookie-based sessions: enable CSRF with token validation:

Java
http.csrf(csrf -> csrf
    .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
);

The frontend reads the XSRF-TOKEN cookie and sends it as X-XSRF-TOKEN header.

Security headers

Java
http.headers(headers -> headers
    .contentSecurityPolicy(csp -> csp
        .policyDirectives("default-src 'self'"))
    .frameOptions(frame -> frame.deny())
    .httpStrictTransportSecurity(hsts -> hsts
        .maxAgeInSeconds(31536000)
        .includeSubDomains(true))
);
HeaderPurpose
Content-Security-PolicyRestrict resource loading sources
X-Frame-Options: DENYPrevent clickjacking
Strict-Transport-SecurityForce HTTPS for one year
X-Content-Type-Options: nosniffPrevent MIME type sniffing
  • Content-Security-Policy

    PurposeRestrict resource loading sources
  • X-Frame-Options: DENY

    PurposePrevent clickjacking
  • Strict-Transport-Security

    PurposeForce HTTPS for one year
  • X-Content-Type-Options: nosniff

    PurposePrevent MIME type sniffing

Production security checklist

Before deploying BookStore

  • Secrets in environment variables — No passwords in application.yml committed to git.
  • HTTPS everywhere — Terminate TLS at the load balancer or ingress; redirect HTTP to HTTPS.
  • Actuator endpoints secured — /actuator/** requires authentication or is disabled.
  • Swagger UI disabled — Or protected behind admin auth in production.
  • Default credentials removed — No user/password from Boot's default security.
  • SQL injection prevented — Use parameterized queries (JPA handles this); never concatenate SQL.
  • Input validation enabled — @Valid on all request DTOs.
  • Dependencies updated — Run ./mvnw versions:display-dependency-updates regularly.
  • Logging sanitised — Never log passwords, tokens, or full credit card numbers.
  • Rate limiting configured — At the gateway or API level to prevent abuse.

Rate limiting example

Java
@Component
public class RateLimitFilter extends OncePerRequestFilter {
    private final Map<String, AtomicInteger> requestCounts = new ConcurrentHashMap<>();

    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                    HttpServletResponse response,
                                    FilterChain chain)
            throws ServletException, IOException {
        String clientIp = request.getRemoteAddr();
        int count = requestCounts
            .computeIfAbsent(clientIp, k -> new AtomicInteger(0))
            .incrementAndGet();

        if (count > 100) {
            response.setStatus(429);
            return;
        }
        chain.doFilter(request, response);
    }
}

Production rate limiting belongs at the API gateway (Kong, AWS WAF) — in-app filters are a starting point.

Error response hygiene

Ensure production error responses never leak internals:

Java
@ExceptionHandler(Exception.class)
public ProblemDetail handleUnexpected(Exception ex) {
    log.error("Unhandled exception", ex);  // full trace in logs
    return ProblemDetail.forStatus(500);    // generic message to client
}

Stack traces, SQL errors, and file paths in HTTP responses are information disclosure vulnerabilities.

Quick recall

Everything you need if you only revisit this box.

  • CORS configures which browser origins can call BookStore API endpoints.
  • Never use allowedOrigins("*") when credentials (cookies) are involved.
  • Disable CSRF only for stateless token-based APIs; keep it for cookie sessions.
  • Set security headers: CSP, HSTS, X-Frame-Options, X-Content-Type-Options.
  • Production checklist: env-var secrets, HTTPS, secured actuator, no default creds.
  • Never expose stack traces or internal details in production error responses.

Test yourself

Answer these before moving on — recall is what makes it stick.