Bug2Lab · Secure Code · Spring Boot Actuator

Открытый Actuator без авторизации

В проде открыт /actuator/** для всех. Любой человек снаружи может посмотреть конфиг, переменные окружения, health-проверки, а иногда даже скачать heap dump сервиса. Фикс — ограничить доступ и выключить чувствительные эндпоинты наружу.

1
Как выглядит атака
Атакующий отправляет:
GET /actuator/env
и получает секреты окружения, в том числе доступ к БД.
GET /actuator/env
200 OK (application/json)
{
 "spring.datasource.password":"ProdDB_Passw0rd!",
 "aws.accessKey":"AKIA...",
 "jwt.signing.key":"super-secret-jwt-key"
}
2
Почему это стало возможным
В приложении Actuator включён полностью (exposure.include=*) и открыт всем без авторизации «на время отладки».
Проблемный код / конфиг
10# application.properties
11management.endpoints.web.exposure.include=*
12management.endpoint.env.show-values=ALWAYS
13
14// SecurityConfig.java
15@Bean
16SecurityFilterChain filter(HttpSecurity http) throws Exception {
17 http.authorizeHttpRequests(auth -> auth
18 .requestMatchers("/actuator/**").permitAll() // ❌ открыт наружу
19 .anyRequest().authenticated()
20 );
21 return http.build();
22}
3
Как это чинится правильно
Мы закрываем чувствительные эндпоинты, ограничиваем видимость и требуем роль. Плюс уносим Actuator в отдельный внутренний порт.
Исправленный паттерн
10# application-prod.properties
11management.endpoints.web.exposure.include=health,info
12management.endpoint.env.show-values=NEVER
13management.server.port=9001
14management.server.address=127.0.0.1 # ✅ только внутри
16// SecurityConfig.java
17@Bean
18SecurityFilterChain filter(HttpSecurity http) throws Exception {
19 http.authorizeHttpRequests(auth -> auth
20 .requestMatchers("/actuator/**").hasRole("ADMIN") // ✅ не для всех
21 .anyRequest().authenticated()
22 );
23 return http.build();
24}

bug2regress Регрессионный тест (стоп-кран)

Скрипт пытается без авторизации сходить в /actuator/env. Если сервер всё ещё отдаёт 200 — билд стопаем. Мы ждём 401 или 403.

#!/bin/bash
# actuator-check.sh

STATUS=$(curl -s -o /tmp/env.json -w "%{http_code}" \
  "https://staging.example.internal/actuator/env")

if [ "$STATUS" = "200" ]; then
  echo "[BLOCK] Actuator/ENV доступен анонимно в стейдже"
  exit 1
fi

echo "[OK] Actuator закрыт извне (HTTP $STATUS)"
exit 0

Это фиксирует правило: чувствительные системные эндпоинты не доступны просто так из интернета.

Проверка понимания В чём была проблема?

Стандарт: Actuator — это не публичная фича для клиента. Это админка. Она должна быть закрыта.

Теория (по желанию) Actuator ≠ «ну просто healthcheck», это админ-панель сервиса