Gymterview
middle

Как обеспечить безопасность REST API?

Безопасность REST API — комплексная задача, включающая несколько уровней защиты: от транспортного шифрования до аудита действий.

Чек-лист безопасности REST API

Уровень Меры
Транспорт HTTPS (TLS) для всех endpoint-ов
Аутентификация JWT / OAuth 2.0 / API Key
Авторизация Ролевая модель (@PreAuthorize)
Валидация Все входные данные (@Valid)
Rate Limiting Защита от DDoS и brute-force
CORS Только доверенные домены
DTO Вместо сущностей в API (защита от Mass Assignment)
Заголовки X-Content-Type-Options, X-Frame-Options, HSTS
Информация Нет утечки стек-трейсов, версий, внутренних ID
Аудит Логирование аутентификации, авторизации, изменений

Защита от массового присваивания (Mass Assignment)

Пример
// Опасно — клиент может передать {"role": "ADMIN"}
@PostMapping
public User create(@RequestBody User user) { ... }

// Безопасно — DTO содержит только допустимые поля
@PostMapping
public UserDto create(@RequestBody CreateUserRequest request) { ... }
Примеры конфигурации Spring Security

Авторизация на уровне методов:

@PreAuthorize("hasRole('ADMIN')")
@DeleteMapping("/users/{id}")
public ResponseEntity<Void> deleteUser(@PathVariable Long id) { ... }

@PreAuthorize("hasRole('USER') and #id == authentication.principal.id")
@GetMapping("/users/{id}/profile")
public ResponseEntity<Profile> getProfile(@PathVariable Long id) { ... }

Защита заголовков:

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    return http
        .headers(headers -> headers
            .contentTypeOptions(Customizer.withDefaults())       // X-Content-Type-Options: nosniff
            .frameOptions(frame -> frame.deny())                  // X-Frame-Options: DENY
            .httpStrictTransportSecurity(hsts -> hsts
                .maxAgeInSeconds(31536000)
                .includeSubDomains(true)))                        // Strict-Transport-Security
        .build();
}

Минимизация раскрытия информации:

server:
  error:
    include-stacktrace: never
    include-message: never

Аудит:

@Aspect
@Component
@Slf4j
public class AuditAspect {

    @AfterReturning("@annotation(auditable)")
    public void audit(JoinPoint joinPoint, Auditable auditable) {
        String user = SecurityContextHolder.getContext()
            .getAuthentication().getName();
        log.info("Audit: user={}, action={}, method={}",
                 user, auditable.action(), joinPoint.getSignature().getName());
    }
}

На собеседовании: нужно перечислить минимум 5-6 уровней защиты из чек-листа. Частая ошибка — говорить только про аутентификацию и забыть про валидацию, CORS, Rate Limiting и DTO.