Spring Boot Security Review
Use when adding auth, handling input, creating endpoints, or dealing with secrets.
Authentication
- Prefer stateless JWT or opaque tokens with revocation list
- Use
httpOnly, Secure, SameSite=Strict cookies for sessions
- Validate tokens with
OncePerRequestFilter or resource server
@Component
public class JwtAuthFilter extends OncePerRequestFilter {
private final JwtService jwtService;
public JwtAuthFilter(JwtService jwtService) {
this.jwtService = jwtService;
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
FilterChain chain) throws ServletException, IOException {
String header = request.getHeader(HttpHeaders.AUTHORIZATION);
if (header != null && header.startsWith("Bearer ")) {
String token = header.substring(7);
Authentication auth = jwtService.authenticate(token);
SecurityContextHolder.getContext().setAuthentication(auth);
}
chain.doFilter(request, response);
}
}
Authorization
- Enable method security:
@EnableMethodSecurity
- Use
@PreAuthorize("hasRole('ADMIN')") or @PreAuthorize("@authz.canEdit(#id)")
- Deny by default; expose only required scopes
Input Validation
- Use Bean Validation with
@Valid on controllers
- Apply constraints on DTOs:
@NotBlank, @Email, @Size, custom validators
- Sanitize any HTML with a whitelist before rendering
SQL Injection Prevention
- Use Spring Data repositories or parameterized queries
- For native queries, use
:param bindings; never concatenate strings
CSRF Protection
- For browser session apps, keep CSRF enabled; include token in forms/headers
- For pure APIs with Bearer tokens, disable CSRF and rely on stateless auth
http
.csrf(csrf -> csrf.disable())
.sessionManagement(sm -> sm.sessionCreationPolicy(SessionCreationPolicy.STATELESS));
Secrets Management
- No secrets in source; load from env or vault
- Keep
application.yml free of credentials; use placeholders
- Rotate tokens and DB credentials regularly
Security Headers
http
.headers(headers -> headers
.contentSecurityPolicy(csp -> csp
.policyDirectives("default-src 'self'"))
.frameOptions(HeadersConfigurer.FrameOptionsConfig::sameOrigin)
.xssProtection(Customizer.withDefaults())
.referrerPolicy(rp -> rp.policy(ReferrerPolicyHeaderWriter.ReferrerPolicy.NO_REFERRER)));
Rate Limiting
- Apply Bucket4j or gateway-level limits on expensive endpoints
- Log and alert on bursts; return 429 with retry hints
Dependency Security
- Run OWASP Dependency Check / Snyk in CI
- Keep Spring Boot and Spring Security on supported versions
- Fail builds on known CVEs
Logging and PII
- Never log secrets, tokens, passwords, or full PAN data
- Redact sensitive fields; use structured JSON logging
File Uploads
- Validate size, content type, and extension
- Store outside web root; scan if required
Checklist Before Release
Remember: Deny by default, validate inputs, least privilege, and secure-by-configuration first.
1---2name: springboot-security3description: Spring Security best practices for authn/authz, validation, CSRF, secrets, headers, rate limiting, and dependency security in Java Spring Boot services.4---5
6# Spring Boot Security Review
7
8Use when adding auth, handling input, creating endpoints, or dealing with secrets.
9
10## Authentication
11
12- Prefer stateless JWT or opaque tokens with revocation list
13- Use `httpOnly`, `Secure`, `SameSite=Strict` cookies for sessions
14- Validate tokens with `OncePerRequestFilter` or resource server
15
16```java
17@Component
18public class JwtAuthFilter extends OncePerRequestFilter {
19 private final JwtService jwtService;
20
21 public JwtAuthFilter(JwtService jwtService) {
22 this.jwtService = jwtService;
23 }
24
25 @Override
26 protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
27 FilterChain chain) throws ServletException, IOException {
28 String header = request.getHeader(HttpHeaders.AUTHORIZATION);
29 if (header != null && header.startsWith("Bearer ")) {
30 String token = header.substring(7);
31 Authentication auth = jwtService.authenticate(token);
32 SecurityContextHolder.getContext().setAuthentication(auth);
33 }
34 chain.doFilter(request, response);
35 }
36}
37```
38
39## Authorization
40
41- Enable method security: `@EnableMethodSecurity`
42- Use `@PreAuthorize("hasRole('ADMIN')")` or `@PreAuthorize("@authz.canEdit(#id)")`
43- Deny by default; expose only required scopes
44
45## Input Validation
46
47- Use Bean Validation with `@Valid` on controllers
48- Apply constraints on DTOs: `@NotBlank`, `@Email`, `@Size`, custom validators
49- Sanitize any HTML with a whitelist before rendering
50
51## SQL Injection Prevention
52
53- Use Spring Data repositories or parameterized queries
54- For native queries, use `:param` bindings; never concatenate strings
55
56## CSRF Protection
57
58- For browser session apps, keep CSRF enabled; include token in forms/headers
59- For pure APIs with Bearer tokens, disable CSRF and rely on stateless auth
60
61```java
62http
63 .csrf(csrf -> csrf.disable())
64 .sessionManagement(sm -> sm.sessionCreationPolicy(SessionCreationPolicy.STATELESS));
65```
66
67## Secrets Management
68
69- No secrets in source; load from env or vault
70- Keep `application.yml` free of credentials; use placeholders
71- Rotate tokens and DB credentials regularly
72
73## Security Headers
74
75```java
76http
77 .headers(headers -> headers
78 .contentSecurityPolicy(csp -> csp
79 .policyDirectives("default-src 'self'"))
80 .frameOptions(HeadersConfigurer.FrameOptionsConfig::sameOrigin)
81 .xssProtection(Customizer.withDefaults())
82 .referrerPolicy(rp -> rp.policy(ReferrerPolicyHeaderWriter.ReferrerPolicy.NO_REFERRER)));
83```
84
85## Rate Limiting
86
87- Apply Bucket4j or gateway-level limits on expensive endpoints
88- Log and alert on bursts; return 429 with retry hints
89
90## Dependency Security
91
92- Run OWASP Dependency Check / Snyk in CI
93- Keep Spring Boot and Spring Security on supported versions
94- Fail builds on known CVEs
95
96## Logging and PII
97
98- Never log secrets, tokens, passwords, or full PAN data
99- Redact sensitive fields; use structured JSON logging
100
101## File Uploads
102
103- Validate size, content type, and extension
104- Store outside web root; scan if required
105
106## Checklist Before Release
107
108- [ ] Auth tokens validated and expired correctly
109- [ ] Authorization guards on every sensitive path
110- [ ] All inputs validated and sanitized
111- [ ] No string-concatenated SQL
112- [ ] CSRF posture correct for app type
113- [ ] Secrets externalized; none committed
114- [ ] Security headers configured
115- [ ] Rate limiting on APIs
116- [ ] Dependencies scanned and up to date
117- [ ] Logs free of sensitive data
118
119**Remember**: Deny by default, validate inputs, least privilege, and secure-by-configuration first.