Clean • Professional
Securing Spring Boot applications is crucial to prevent data breaches, unauthorized access, and other security threats. While Spring Security provides robust defaults, following best practices ensures your application remains safe, scalable, and maintainable.
Cross-Site Request Forgery (CSRF) is an attack where a malicious site tricks a logged-in user into performing unwanted actions on your application.
Example:
A user is logged into a banking site. A malicious website sends a hidden request to transfer money using the user’s session. If CSRF protection isn’t enabled, the request succeeds without the user knowing.
Best Practices:
Disable CSRF (commonly for REST APIs):
http
.csrf().disable();
Enable CSRF (default for web apps):
http
.csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
Spring Security automatically adds CSRF tokens to forms and validates them during POST, PUT, DELETE requests.
Why it matters:
Always enable CSRF for web forms; disable only when building stateless APIs secured by tokens
Cross-Origin Resource Sharing (CORS) is a security feature in browsers that controls which domains can access your APIs. Without proper configuration, browsers block requests coming from untrusted origins.
Best Practices:
"*" in productionCorsConfiguration or @CrossOrigin for fine-grained controlGET, POST, PUT, DELETE)Example – Global CORS Configuration in Spring Boot
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
publicclassCorsConfig {
@Bean
public WebMvcConfigurercorsConfigurer() {
returnnewWebMvcConfigurer() {
@Override
publicvoidaddCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**")
.allowedOrigins("<https://trusteddomain.com>")
.allowedMethods("GET","POST","PUT","DELETE")
.allowCredentials(true);
}
};
}
}
Alternative – Using @CrossOrigin on Controller
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@CrossOrigin(origins = "<https://trusteddomain.com>",
allowedHeaders = "*",
allowCredentials = "true")
publicclassApiController {
@GetMapping("/api/data")
public StringgetData() {
return"Protected API Data";
}
}
Why it matters:
A brute force attack is when attackers repeatedly try to guess user credentials, usually passwords, by submitting multiple login attempts.
Best Practices:
Example – Simplified Login Attempt Check
public void login(String username, String password) {
if (loginAttemptsService.getAttempts(username) > MAX_ATTEMPTS) {
throw new AccountLockedException("Too many failed login attempts. Try again later.");
}
boolean success = authenticationService.authenticate(username, password);
if (!success) {
loginAttemptsService.incrementAttempts(username);
} else {
loginAttemptsService.resetAttempts(username);
}
}
Why it matters:
Security headers protect users from common web attacks, including:
They are a first line of defense in your web application security.
Recommended Headers in Spring Security:
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
http
.headers()
// Enable XSS protection
.xssProtection()
// Content Security Policy: restrict scripts to same origin
.contentSecurityPolicy("script-src 'self'")
// Prevent embedding in iframes (clickjacking protection)
.frameOptions().deny()
// Enforce HTTPS (HSTS)
.httpStrictTransportSecurity()
.includeSubDomains(true)
.maxAgeInSeconds(31536000);
Key Headers:
X-Content-Type-Options: nosniff → Prevents MIME-type sniffing by browsersX-XSS-Protection: 1; mode=block → Enables browser XSS filteringContent-Security-Policy → Controls which resources can be loaded/executedStrict-Transport-Security (HSTS) → Forces HTTPS and protects against protocol downgrade attacksBest Practice:
REST APIs are often publicly accessible, making them attractive targets for attackers. Secure REST APIs ensure that only authorized users or services can access sensitive endpoints and data.
Best Practices:
@PreAuthorize for role- or scope-based accessExample – JWT Authorization Filter:
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.filter.OncePerRequestFilter;
import java.io.IOException;
public class JwtAuthorizationFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain chain) throws ServletException, IOException {
String token = extractToken(request);
if (token != null && validateToken(token)) {
Authentication auth = getAuthentication(token);
SecurityContextHolder.getContext().setAuthentication(auth);
}
chain.doFilter(request, response);
}
private String extractToken(HttpServletRequest request) {
// Extract token from Authorization header
String header = request.getHeader("Authorization");
return (header != null && header.startsWith("Bearer "))
? header.substring(7) : null;
}
private boolean validateToken(String token) {
// Token validation logic (signature, expiry)
return true;
}
private Authentication getAuthentication(String token) {
// Return Authentication object based on token claims
return null;
}
}
| Area | Best Practice |
|---|---|
| CSRF | Enable for stateful apps; disable for stateless APIs |
| CORS | Restrict access to trusted domains only |
| Brute Force | Limit login attempts, apply lockouts, use exponential backoff |
| Security Headers | Enable XSS protection, HSTS, CSP, and Frame Options |
| REST APIs | Use JWT/OAuth2, validate tokens on every request, enforce method-level security, apply rate limiting |
Following these Spring Security Best Practices ensures your applications are resilient, secure, and production-ready:
Applying these practices alongside Spring Security’s defaults provides comprehensive, layered defense against web and API threats.