
关于
Spring Security 在 Java Spring Boot 服务中的最佳实践,涵盖认证/授权、输入验证、CSRF 防护、密钥管理、安全头配置、速率限制和依赖安全。
name: springboot-security description: Spring Security 最佳实践,涵盖认证/授权、验证、CSRF、密钥管理、安全头、速率限制和 Java Spring Boot 服务的依赖安全。 origin: ECC
Spring Boot 安全审查
在添加认证、处理输入、创建端点或处理密钥时使用。
何时激活
- 添加认证(JWT、OAuth2、基于会话)
- 实现授权(@PreAuthorize、基于角色的访问)
- 验证用户输入(Bean Validation、自定义验证器)
- 配置 CORS、CSRF 或安全头
- 管理密钥(Vault、环境变量)
- 添加速率限制或暴力破解防护
- 扫描依赖的 CVE
认证
- 优先使用无状态 JWT 或带撤销列表的不透明令牌
- 会话使用
httpOnly、Secure、SameSite=Strictcookie - 使用
OncePerRequestFilter或资源服务器验证令牌
@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);
}
}
授权
- 启用方法安全:
@EnableMethodSecurity - 使用
@PreAuthorize("hasRole('ADMIN')")或@PreAuthorize("@authz.canEdit(#id)") - 默认拒绝;仅暴露所需范围
@RestController
@RequestMapping("/api/admin")
public class AdminController {
@PreAuthorize("hasRole('ADMIN')")
@GetMapping("/users")
public List<UserDto> listUsers() {
return userService.findAll();
}
@PreAuthorize("@authz.isOwner(#id, authentication)")
@DeleteMapping("/users/{id}")
public ResponseEntity<Void> deleteUser(@PathVariable Long id) {
userService.delete(id);
return ResponseEntity.noContent().build();
}
}
输入验证
- 在控制器上使用 Bean Validation 的
@Valid - 在 DTO 上应用约束:
@NotBlank、@Email、@Size、自定义验证器 - 渲染前使用白名单清理任何 HTML
// BAD: No validation
@PostMapping("/users")
public User createUser(@RequestBody UserDto dto) {
return userService.create(dto);
}
// GOOD: Validated DTO
public record CreateUserDto(
@NotBlank @Size(max = 100) String name,
@NotBlank @Email String email,
@NotNull @Min(0) @Max(150) Integer age
) {}
@PostMapping("/users")
public ResponseEntity<UserDto> createUser(@Valid @RequestBody CreateUserDto dto) {
return ResponseEntity.status(HttpStatus.CREATED)
.body(userService.create(dto));
}
SQL 注入防护
- 使用 Spring Data 仓库或参数化查询
- 原生查询使用
:param绑定;绝不拼接字符串
// BAD: String concatenation in native query
@Query(value = "SELECT * FROM users WHERE name = '" + name + "'", nativeQuery = true)
// GOOD: Parameterized native query
@Query(value = "SELECT * FROM users WHERE name = :name", nativeQuery = true)
List<User> findByName(@Param("name") String name);
// GOOD: Spring Data derived query (auto-parameterized)
List<User> findByEmailAndActiveTrue(String email);
密码编码
- 始终使用 BCrypt 或 Argon2 哈希密码 — 绝不存储明文
- 使用
PasswordEncoderbean,而非手动哈希
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder(12); // cost factor 12
}
// In service
public User register(CreateUserDto dto) {
String hashedPassword = passwordEncoder.encode(dto.password());
return userRepository.save(new User(dto.name(), dto.email(), hashedPassword));
}
兼容工具
Claude CodeCursor
标签
安全
