OWASP Top 10 for Spring Apps

The List and the Spring Fix

The OWASP Top 10 is the industry list of the most common web application risks. Here is each one with what to do in a Spring Boot app:

#RiskSpring Boot defence
A01Broken Access Control (IDOR, missing checks)deny by default (anyRequest().authenticated()), ownership checks with @PreAuthorize/@PostAuthorize, access-matrix tests
A02Cryptographic FailuresHTTPS + HSTS, BCrypt/Argon2 for passwords, encrypt sensitive columns, no secrets in tokens
A03Injection (SQL, JPQL, command)Spring Data / JPA parameters, never concatenate SQL; Bean Validation on input
A04Insecure Designthreat modelling, rate limits, business rules (max quantity, price from DB not client)
A05Security Misconfigurationno default passwords, Actuator locked down, error pages without stack traces, security headers
A06Vulnerable and Outdated Componentskeep Spring Boot patched, OWASP Dependency-Check / Dependabot / Snyk in CI
A07Identification and Authentication FailuresMFA, lockout + rate limiting, short-lived tokens, session fixation protection (default on)
A08Software and Data Integrity Failuressigned artifacts, verified CI pipelines, no Java deserialization of untrusted data
A09Security Logging and Monitoring Failuresaudit logins and access denials, alerts on spikes
A10Server-Side Request Forgery (SSRF)allow-list hosts when fetching user-supplied URLs (e.g. "import product image from URL")

A01 in Practice: Never Trust the Client

// BAD: customerId and price come from the request
@PostMapping("/api/orders")
public Order place(@RequestBody OrderRequest req) {
    return orderService.create(req.customerId(), req.items(), req.totalPrice());
}

// GOOD: identity from the token, prices from the database
@PostMapping("/api/orders")
public OrderDto place(@AuthenticationPrincipal Jwt jwt, @Valid @RequestBody PlaceOrderRequest req) {
    return orderService.create(jwt.getSubject(), req.items());   // service loads each Product.price itself
}

A05: Lock Down Actuator

application-prod.yml

management:
  endpoints:
    web:
      exposure:
        include: health, info, prometheus     # never "*" in production
  endpoint:
    health:
      show-details: when-authorized
server:
  error:
    include-stacktrace: never
    include-message: never
.requestMatchers(EndpointRequest.to(HealthEndpoint.class, InfoEndpoint.class)).permitAll()
.requestMatchers(EndpointRequest.toAnyEndpoint()).hasRole("OPS")

Note: An exposed /actuator/heapdump or /actuator/env leaks database passwords and live session tokens. It is one of the most common real-world Spring Boot breaches.