CWE-284 in Spring Boot
How Cwe 284 Manifests in Spring Boot
CWE-284 (Improper Access Control) in Spring Boot applications often stems from misconfigured security annotations, missing authentication checks, and improper method-level authorization. The Spring Boot ecosystem provides powerful security features, but improper implementation can create significant vulnerabilities.
Common Spring Boot-specific manifestations include:
- Missing @PreAuthorize or @PostAuthorize annotations on controller methods that should be restricted
- Incorrect use of @RolesAllowed with Spring Security's default configuration
- Public endpoints that should require authentication
- Improper method-level security in service layer components
- Authentication bypass through misconfigured security filters
Consider this vulnerable Spring Boot controller:
@RestController
@RequestMapping("/api/users")
public class UserController {
@Autowired
private UserService userService;
// Vulnerable: Missing authentication check
@GetMapping("/{id}")
public User getUser(@PathVariable Long id) {
return userService.findById(id); // Anyone can access any user's data
}
// Vulnerable: Missing authorization check
@PostMapping
public User createUser(@RequestBody User user) {
return userService.save(user); // No role-based access control
}
}This code allows any unauthenticated user to retrieve user data and create new users, violating the principle of least privilege. The vulnerability becomes more severe when combined with Spring Boot's default security configurations, which may not enforce authentication on all endpoints.
Another Spring Boot-specific scenario involves improper use of @AuthenticationPrincipal:
@RestController
@RequestMapping("/api/orders")
public class OrderController {
@Autowired
private OrderService orderService;
// Vulnerable: Missing @AuthenticationPrincipal check
@GetMapping("/my-orders")
public List getMyOrders() {
// No verification that the user owns these orders
return orderService.findAll();
}
} Here, the method should verify that the authenticated user only accesses their own orders, but the implementation returns all orders without any ownership validation.
Spring Boot-Specific Detection
Detecting CWE-284 vulnerabilities in Spring Boot requires examining both code structure and runtime behavior. middleBrick's Spring Boot-specific scanning includes:
Static Analysis: middleBrick examines Spring Boot application context files, controller classes, and security configurations to identify missing authentication annotations, improper security configurations, and exposed endpoints.
Runtime Scanning: The scanner tests actual API endpoints to verify authentication requirements and authorization controls are properly enforced.
Here's how middleBrick detects common Spring Boot access control issues:
$ middlebrick scan https://api.example.com --profile spring-boot
=== Spring Boot Security Analysis ===
Authentication Issues Detected:
- Endpoint /api/users/{id} (GET): Missing @PreAuthorize
- Endpoint /api/users (POST): Missing authentication
- Endpoint /api/orders/my-orders: Missing user ownership validation
Authorization Issues:
- Method createOrder in OrderService: Missing role check
- Method deleteUser in UserService: Missing admin role requirement
Security Configuration:
- SecurityConfig.java: Missing CSRF protection for state-changing operations
- WebSecurityConfig: PermitAll() applied to sensitive endpoints
Risk Score: D (65/100)
Recommendations:
1. Add @PreAuthorize("hasRole('USER')") to user endpoints
2. Implement @AuthenticationPrincipal validation
3. Configure proper security filter chain
middleBrick also analyzes Spring Boot's security configuration files:
// Vulnerable Spring Boot SecurityConfig
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Autowired
private UserDetailsService userDetailsService;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable() // Problematic if not properly justified
.authorizeRequests()
.antMatchers("/api/public/**").permitAll()
.anyRequest().authenticated(); // Missing specific endpoint protection
}
}
// Secure version
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
.and()
.authorizeRequests()
.antMatchers("/api/public/**").permitAll()
.antMatchers("/api/users/**").hasRole("USER")
.antMatchers("/api/admin/**").hasRole("ADMIN")
.anyRequest().authenticated();
}
}The scanner identifies missing security annotations, improper method-level security, and configuration issues that could lead to access control bypass.
Spring Boot-Specific Remediation
Spring Boot provides multiple layers of security that can be combined to address CWE-284 vulnerabilities effectively. Here are Spring Boot-specific remediation strategies:
Method-Level Security with @PreAuthorize:
@RestController
@RequestMapping("/api/users")
public class UserController {
@Autowired
private UserService userService;
// Secure: Requires authentication and USER role
@GetMapping("/{id}")
@PreAuthorize("hasRole('USER') and #id == authentication.principal.id or hasRole('ADMIN')")
public User getUser(@PathVariable Long id, @AuthenticationPrincipal UserPrincipal user) {
return userService.findById(id);
}
// Secure: Requires ADMIN role
@PostMapping
@PreAuthorize("hasRole('ADMIN')")
public User createUser(@RequestBody User user) {
return userService.save(user);
}
}Service Layer Security:
@Service
public class OrderService {
@Autowired
private OrderRepository orderRepository;
// Secure: Verifies user ownership
@PreAuthorize("#userId == authentication.principal.id or hasRole('ADMIN')")
public List getOrdersForUser(Long userId) {
return orderRepository.findByUserId(userId);
}
// Secure: Admin-only deletion
@PreAuthorize("hasRole('ADMIN')")
public void deleteOrder(Long orderId, Long userId) {
Order order = orderRepository.findById(orderId)
.orElseThrow(() -> new OrderNotFoundException(orderId));
if (!order.getUserId().equals(userId) && !hasRole("ADMIN")) {
throw new AccessDeniedException("Unauthorized order deletion");
}
orderRepository.delete(order);
}
} Controller-Level Security with @Secured:
@RestController
@RequestMapping("/api/admin")
@Secured("ROLE_ADMIN")
public class AdminController {
@Autowired
private AdminService adminService;
// All methods require ADMIN role
@GetMapping("/users")
public List getAllUsers() {
return adminService.getAllUsers();
}
@DeleteMapping("/users/{id}")
public void deleteUser(@PathVariable Long id) {
adminService.deleteUser(id);
}
} Custom Security Expressions:
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
@Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
return new OAuth2MethodSecurityExpressionHandler();
}
@Bean
public PermissionEvaluator permissionEvaluator() {
return new CustomPermissionEvaluator();
}
}
// Custom permission evaluator for complex authorization
public class CustomPermissionEvaluator implements PermissionEvaluator {
@Override
public boolean hasPermission(Authentication authentication, Object targetDomainObject, Object permission) {
if (targetDomainObject instanceof Order) {
Order order = (Order) targetDomainObject;
UserPrincipal user = (UserPrincipal) authentication.getPrincipal();
if (permission.equals("read") && order.getUserId().equals(user.getId())) {
return true;
}
if (permission.equals("delete") && user.hasRole("ADMIN")) {
return true;
}
}
return false;
}
}Security Configuration Best Practices:
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf(csrf -> csrf.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()))
.authorizeRequests(auth -> auth
.requestMatchers(EndpointRequest.toAnyEndpoint()).hasRole("ADMIN")
.requestMatchers("/api/public/**").permitAll()
.requestMatchers("/api/users/**").hasRole("USER")
.requestMatchers("/api/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
)
.sessionManagement(session -> session
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
)
.exceptionHandling(exception -> exception
.accessDeniedHandler(new CustomAccessDeniedHandler())
.authenticationEntryPoint(new CustomAuthenticationEntryPoint())
);
}
}These Spring Boot-specific patterns ensure proper access control throughout the application stack, addressing CWE-284 vulnerabilities at both the controller and service layers.
Frequently Asked Questions
How does Spring Boot's default security configuration affect CWE-284 vulnerabilities?
Spring Boot's default security configuration provides basic authentication but may not cover all endpoints. By default, Spring Boot Security auto-configures basic authentication for actuator endpoints and requires authentication for all other endpoints. However, this default behavior can create a false sense of security. Developers often assume all endpoints are protected when they actually need explicit configuration. middleBrick's scanning identifies these gaps by testing unauthenticated access to all endpoints and verifying that sensitive operations require proper authentication and authorization.
Can middleBrick detect CWE-284 issues in Spring Boot actuator endpoints?
Yes, middleBrick specifically tests Spring Boot actuator endpoints for improper access control. Actuator endpoints often contain sensitive information about application health, configuration, and metrics. The scanner verifies that endpoints like /actuator/env, /actuator/configprops, and /actuator/beans are properly secured and not publicly accessible. middleBrick checks for missing @PreAuthorize annotations on actuator endpoints and tests whether unauthenticated users can access sensitive operational data that could aid attackers in reconnaissance.