Segurança: Como fortalecer a segurança do seu backend Spring
Medidas essenciais para proteger APIs Spring: autenticação, autorização, OWASP, segredos, headers e monitoramento.
A segurança em aplicações Spring Boot não é mais uma opção, mas sim uma necessidade crítica. Com o aumento das ameaças cibernéticas e a crescente dependência de APIs, proteger adequadamente seu backend se tornou fundamental para o sucesso de qualquer projeto. Neste artigo, vamos explorar as práticas mais eficazes para blindar sua aplicação Spring contra vulnerabilidades comuns.
1. Configuração de Autenticação e Autorização Robusta
O Spring Security oferece um framework completo para implementar autenticação e autorização. A configuração adequada é o primeiro passo para uma aplicação segura:
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
return http
.csrf(csrf -> csrf.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()))
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/public/**").permitAll()
.requestMatchers("/api/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
)
.oauth2ResourceServer(oauth2 -> oauth2.jwt(Customizer.withDefaults()))
.sessionManagement(session -> session
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
)
.build();
}
}
Implementação de JWT Seguro
Para APIs RESTful, o uso de JWT (JSON Web Tokens) é uma prática comum, mas deve ser implementado com cuidado:
- Use algoritmos seguros: Prefira RS256 ou ES256 ao invés de HS256
- Defina expiração adequada: Tokens de acesso devem ter vida curta (15-30 minutos)
- Implemente refresh tokens: Para renovar tokens de acesso sem forçar novo login
- Validação rigorosa: Sempre valide a assinatura, expiração e claims essenciais
2. Proteção Contra Vulnerabilidades OWASP Top 10
Injeção SQL e NoSQL
O Spring Data oferece proteções nativas, mas é essencial seguir as melhores práticas:
// ✅ Correto - usando @Query com parâmetros nomeados
@Query("SELECT u FROM User u WHERE u.email = :email")
Optional<User> findByEmail(@Param("email") String email);
// ❌ Evitar - concatenação de strings
// Query nativa vulnerável a SQL injection
Cross-Site Scripting (XSS)
Configure adequadamente os headers de segurança e sanitização:
@Configuration
public class WebSecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
return http
.headers(headers -> headers
.frameOptions().deny()
.contentTypeOptions().and()
.xssProtection().and()
.referrerPolicy(ReferrerPolicy.STRICT_ORIGIN_WHEN_CROSS_ORIGIN)
.httpStrictTransportSecurity(hsts -> hsts
.maxAgeInSeconds(31536000)
.includeSubdomains(true)
)
)
.build();
}
}
3. Gerenciamento Seguro de Segredos
Nunca exponha credenciais no código ou repositórios. Use ferramentas apropriadas:
Spring Cloud Config + Vault
# application.yml
spring:
cloud:
vault:
host: vault.example.com
port: 8200
scheme: https
authentication: TOKEN
token: ${VAULT_TOKEN}
kv:
enabled: true
backend: secret
profile-separator: '/'
default-context: application
Variáveis de Ambiente
// ✅ Correto
@Value("${database.password}")
private String databasePassword;
// ❌ Evitar
private String databasePassword = "minhasenha123";
4. Validação e Sanitização Rigorosa
Implemente validação em múltiplas camadas usando Bean Validation:
@RestController
@Validated
public class UserController {
@PostMapping("/users")
public ResponseEntity<User> createUser(
@Valid @RequestBody CreateUserRequest request) {
// Lógica de criação
return ResponseEntity.ok(userService.create(request));
}
}
@Data
public class CreateUserRequest {
@NotBlank(message = "Nome é obrigatório")
@Size(min = 2, max = 100, message = "Nome deve ter entre 2 e 100 caracteres")
private String name;
@Email(message = "Email deve ser válido")
@NotBlank(message = "Email é obrigatório")
private String email;
@Pattern(regexp = "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[@$!%*?&])[A-Za-z\\d@$!%*?&]{8,}$",
message = "Senha deve ter pelo menos 8 caracteres, incluindo maiúscula, minúscula, número e símbolo")
private String password;
}
5. Logging e Monitoramento de Segurança
Implemente logs de auditoria e monitoramento proativo:
@Component
@Slf4j
public class SecurityAuditListener {
@EventListener
public void handleAuthenticationSuccess(AuthenticationSuccessEvent event) {
String username = event.getAuthentication().getName();
String clientIp = getClientIp();
log.info("LOGIN_SUCCESS: user={}, ip={}, timestamp={}",
username, clientIp, Instant.now());
}
@EventListener
public void handleAuthenticationFailure(AbstractAuthenticationFailureEvent event) {
String username = event.getAuthentication().getName();
String clientIp = getClientIp();
String reason = event.getException().getMessage();
log.warn("LOGIN_FAILURE: user={}, ip={}, reason={}, timestamp={}",
username, clientIp, reason, Instant.now());
// Alertar sistema de detecção de intrusão se necessário
checkForBruteForceAttack(clientIp);
}
}
6. Rate Limiting e Proteção contra DDoS
Implemente limitação de taxa para prevenir ataques de força bruta:
@Component
public class RateLimitingFilter implements Filter {
private final Map<String, RateLimiter> rateLimiters = new ConcurrentHashMap<>();
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
String clientIp = getClientIp(httpRequest);
RateLimiter limiter = rateLimiters.computeIfAbsent(clientIp,
key -> RateLimiter.create(10.0)); // 10 requests per second
if (limiter.tryAcquire()) {
chain.doFilter(request, response);
} else {
HttpServletResponse httpResponse = (HttpServletResponse) response;
httpResponse.setStatus(HttpStatus.TOO_MANY_REQUESTS.value());
httpResponse.getWriter().write("{\"error\": \"Rate limit exceeded\"}");
}
}
}
7. HTTPS e Configurações de TLS
Configure adequadamente o HTTPS em produção:
# application-prod.yml
server:
port: 8443
ssl:
enabled: true
key-store: classpath:keystore.p12
key-store-password: ${SSL_KEYSTORE_PASSWORD}
key-store-type: PKCS12
key-alias: spring
protocol: TLS
enabled-protocols: TLSv1.3,TLSv1.2
# Redirecionar HTTP para HTTPS
http:
port: 8080
redirect-to-https: true
8. Testes de Segurança Automatizados
Inclua testes de segurança na sua pipeline de CI/CD:
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class SecurityIntegrationTest {
@Autowired
private TestRestTemplate restTemplate;
@Test
void shouldRejectUnauthorizedAccess() {
ResponseEntity<String> response = restTemplate.getForEntity("/api/protected", String.class);
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);
}
@Test
void shouldRejectMaliciousInput() {
String maliciousInput = "<script>alert('xss')</script>";
ResponseEntity<String> response = restTemplate.postForEntity("/api/users",
Map.of("name", maliciousInput), String.class);
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.BAD_REQUEST);
}
}
Conclusão
A segurança em aplicações Spring é um processo contínuo que requer atenção constante. As práticas apresentadas neste artigo formam uma base sólida para proteger seu backend, mas lembre-se de que a segurança evolui constantemente.
Pontos-chave para implementar:
- Configure adequadamente autenticação e autorização
- Proteja contra vulnerabilidades OWASP Top 10
- Gerencie segredos de forma segura
- Implemente validação rigorosa
- Configure logging e monitoramento
- Use HTTPS em produção
- Automatize testes de segurança
Mantenha-se atualizado com as melhores práticas de segurança e considere realizar auditorias regulares em suas aplicações. A segurança não é um destino, mas uma jornada contínua de melhoria e vigilância.