Spring Boot — безопасность в продакшене
Spring Boot — безопасность в продакшене
После практического старта Spring Security и JWT / Resource Server приложение защищено на уровне «учебного API». В production нужен отдельный слой: транспорт, заголовки, секреты, зависимости и процессы команды.
Ниже — десять практик, которые обычно входят в чеклист для Spring Boot (в духе industry cheat sheet от Snyk и Java Champions). Все примеры — Spring Security 6 и SecurityFilterChain, без устаревшего WebSecurityConfigurerAdapter.
Связанные материалы
| Тема | Где углубиться |
|---|---|
| OAuth2 / OIDC, Keycloak | Основы ИБ — SSO |
| CSP, XSS, CSRF в браузере | Как работают сайты — безопасность, CSP |
| Сканирование зависимостей в CI | DevOps — SCA, конвейеры |
| Секреты вне Git | Забота о коде и данных |
Профили и application-prod | Рекомендации по Java — профили |
Сводный чеклист
| № | Практика | Зачем |
|---|---|---|
| 1 | HTTPS в prod | Шифрование трафика, защита cookie и токенов от перехвата |
| 2 | Проверка зависимостей (SCA) | Известные CVE в spring-*, Log4j, Jackson и транзитивных JAR |
| 3 | CSRF для stateful web | Подставные запросы из чужого сайта с cookie сессии |
| 4 | Content Security Policy | Снижение риска XSS — белый список источников скриптов |
| 5 | OpenID Connect | Делегированный вход (Google, Keycloak, корпоративный IdP) |
| 6 | Хеширование паролей | Пароли в БД только через PasswordEncoder |
| 7 | Актуальные версии Spring Boot / JDK | Закрытие уязвимостей в платформе |
| 8 | Секреты в vault / env | Пароли БД и API-ключи вне репозитория |
| 9 | Пентест / DAST | OWASP ZAP, активное сканирование staging |
| 10 | Security-ревью и gates в PR | Человек + автоматика на каждом merge |
1. HTTPS в production
Терминация TLS чаще всего на reverse proxy (nginx, Ingress, API Gateway). Spring Boot может дополнительно требовать HTTPS на уровне приложения:
@Bean
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.requiresChannel(channel -> channel.anyRequest().requiresSecure());
// authorizeHttpRequests, csrf, oauth2ResourceServer...
return http.build();
}
Правило requiresSecure() заставит браузер ходить по https://localhost. Для dev вынесите настройку в профиль или отключите канал в application-dev.yml. В prod TLS обязателен на границе сети; см. также заголовок Strict-Transport-Security в безопасности веб-приложений.
2. Тестировать зависимости на уязвимости
Spring Boot тянет десятки транзитивных библиотек. Software Composition Analysis (SCA) сравнивает версии с базой CVE.
| Инструмент | Типичное место |
|---|---|
| OWASP Dependency-Check | Maven/Gradle plugin, отчёт в CI |
| Snyk, Dependabot, Renovate | PR с обновлением уязвимых версий |
| Trivy | Образ Docker + зависимости |
Минимум для команды: скан mvn dependency:tree / Gradle lockfile на каждом PR и блокировка merge при Critical/High без исключения. Подробнее — SCA в DevOps.
<!-- пример: OWASP Dependency-Check в Maven -->
<plugin>
<groupId>org.owasp</groupId>
<artifactId>dependency-check-maven</artifactId>
<version>11.1.0</version>
<executions>
<execution>
<goals><goal>check</goal></goals>
</execution>
</executions>
</plugin>
3. CSRF — включать осознанно
Spring Security включает CSRF по умолчанию для приложений с сессией в cookie. В учебном REST CSRF отключали, потому что клиент шлёт только Authorization: Bearer без cookie.
Для SPA + cookie-сессия или классических форм нужна CSRF-защита. Если фронтенд читает токен из cookie, cookie не должна быть HttpOnly:
http.csrf(csrf -> csrf
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()));
Клиент (React, Vue) читает cookie XSRF-TOKEN и дублирует значение в заголовке X-XSRF-TOKEN при POST/PUT/DELETE. Теория — CSRF в веб-безопасности.
4. Content Security Policy (CSP)
Spring Security по умолчанию выставляет ряд security-заголовков, но CSP нужно задать явно:
http.headers(headers -> headers
.contentSecurityPolicy(csp -> csp.policyDirectives(
"default-src 'self'; " +
"script-src 'self' https://trustedscripts.example.com; " +
"object-src 'none'; " +
"report-uri /csp-report-endpoint/")));
Сначала политику можно включить в режиме Content-Security-Policy-Report-Only, собрать отчёты с /csp-report-endpoint/, затем ужесточить. Директивы и отчёты — Reporting API и CSP.
5. OpenID Connect (OIDC)
OIDC поверх OAuth2 добавляет ID Token (кто вошёл) и стандартный endpoint /userinfo для профиля.
В Spring Boot:
- Клиент (браузерный вход «через Google») —
spring-boot-starter-oauth2-client; - Resource Server (API принимает JWT) —
spring-boot-starter-oauth2-resource-server, см. JWT в Spring Boot.
# application.yml — resource server против Keycloak / Auth0
spring:
security:
oauth2:
resourceserver:
jwt:
issuer-uri: https://idp.example.com/realms/my-realm
Роли из токена маппятся на GrantedAuthority; сценарий с Keycloak разобран в примере REST + Keycloak.
6. Хеширование паролей
Пароли никогда не хранят в открытом виде и не сравнивают строкой password.equals(stored).
Интерфейс Spring Security:
public interface PasswordEncoder {
String encode(CharSequence rawPassword);
boolean matches(CharSequence rawPassword, String encodedPassword);
}
Типичная настройка:
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
// при регистрации
user.setPassword(passwordEncoder.encode(rawPassword));
// при логине Spring сравнивает через UserDetailsService + PasswordEncoder
Префикс {noop} из учебного примера допустим только в тестах. В БД — bcrypt, scrypt или делегирование в IdP (OIDC).
7. Актуальные релизы Spring Boot и JDK
Spring Initializr для новых проектов подтягивает свежие patch-версии BOM. Для существующих сервисов:
- следите за Spring Boot release notes и CVE;
- держите LTS JDK (17 или 21);
- обновляйте patch (
3.4.x→3.4.y) по расписанию, major — по плану миграции.
Если обновление отложено, SCA и vendor-патчи закрывают часть уязвимостей в транзитивных JAR без смены major Spring.
8. Секреты вне кода и Git
Антипаттерн — пароль БД в application.properties в репозитории:
# так делать нельзя в prod
spring.datasource.password=SuperSecret123
Правильные варианты:
| Способ | Когда |
|---|---|
Переменные окружения SPRING_DATASOURCE_PASSWORD | Kubernetes, VM, PaaS |
| HashiCorp Vault, Spring Cloud Vault | Централизованное хранение, ротация |
| Секреты CI/CD (GitLab Variables, GitHub Secrets) | Деплой без записи в образ |
@Value("${db.password}")
String password; // значение приходит из vault/env при старте, не из Git
См. профили окружений и гигиену секретов.
9. Пентест и динамическое сканирование
OWASP ZAP (и аналоги) прогоняют staging: Spider находит ссылки, Active Scan — типовые уязвимости (XSS, SQLi, misconfiguration).
| Режим | Назначение |
|---|---|
| Spider | Карта URL приложения |
| Active Scan | Автоматические проверки по найденным точкам |
| API Scan | OpenAPI/Swagger для REST |
ZAP встраивают в CI как DAST после деплоя на test/stage — DevOps и OWASP ZAP. Результаты согласуют с ручным пентестом перед релизом.
10. Security-ревью и автоматика в pull request
Процесс дополняет технические настройки:
- Ревью изменений в
SecurityFilterChain, новых эндпоинтах, CORS, маппинге ролей — желательно с участием security-чемпиона команды; - SAST/SCA (SonarQube, Snyk, Dependency-Check) на каждом PR;
- Чеклист для автора: новые публичные URL? секреты в диффе? логируются ли токены?
Связка с тестированием: security-сценарии в @WebMvcTest / @SpringBootTest с @WithMockUser, как в статье 272.
Пример — фрагмент prod-конфигурации
Объединение нескольких пунктов (упрощённо; политику URL подставьте под свой API):
@Configuration
@EnableWebSecurity
@Profile("prod")
public class ProductionSecurityConfig {
@Bean
SecurityFilterChain prodChain(HttpSecurity http) throws Exception {
http
.requiresChannel(ch -> ch.anyRequest().requiresSecure())
.csrf(csrf -> csrf
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()))
.headers(h -> h.contentSecurityPolicy(csp -> csp.policyDirectives(
"default-src 'self'; script-src 'self'; frame-ancestors 'none'")))
.authorizeHttpRequests(auth -> auth
.requestMatchers("/actuator/health", "/actuator/info").permitAll()
.requestMatchers("/actuator/**").hasRole("ADMIN")
.anyRequest().authenticated())
.oauth2ResourceServer(oauth2 -> oauth2.jwt(Customizer.withDefaults()));
return http.build();
}
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
271 Spring Boot → 272 Security старт → 274 JWT → эта статья → 303 ошибки REST → 291 тесты.
Частые ошибки
| Ошибка | Последствие | Что сделать |
|---|---|---|
| CSRF отключён «навсегда» после REST-туториала | CSRF на формах с cookie | Включить CSRF для web UI; для pure Bearer API оставить off |
| Секреты в Git | Утечка при fork/clone | Env, Vault, ротация ключей |
| Только unit-тесты без ZAP/SCA | CVE и misconfig в prod | SCA в CI + DAST на stage |
{noop} или MD5 для паролей | Мгновенный компромисс БД | BCryptPasswordEncoder или OIDC |
| CSP не настроен | XSS через inline-скрипт | CSP + экранирование на фронте |
Spring Security — старт · JWT · Spring Framework · Информационная безопасность
См. также
Другие статьи этого же раздела в боковом меню (как на странице "О разделе"). Основы Java - устройство JDK/JVM, модель компиляции и базовые принципы платформонезависимого выполнения. Java — объектно-ориентированный язык общего назначения с принципом «напиши один раз, запускай в любом месте». Набор советов, правил, принципов и обычаев в разработке на этом языке. История Java — от проекта Green и Oak до OpenJDK, LTS-релизов и современной платформы (модули, records, виртуальные потоки). Библиотеки, фреймворки, инструменты сборки, тестирования, развёртывания и мониторинга. Что такое пакет и пакетная структура, как собираются проекты на Java. Справочник-шпаргалка по конфигурациям в Java — типы, синтаксис, стандартная библиотека, типовые паттерны. Не заменяет пошаговое обучение. Учебный курс — раздел. Гайд по установке и настройке с написанием первой программы и её запуском. Практические примеры — консольные утилиты, композиция классов и первое Swing-приложение. Точки останова, пошаговое выполнение, панели Variables и Call Stack — практика отладки в IntelliJ IDEA. Кавычки, точки, запятые, скобки и прочие знаки препинания. Это полный справочник всех ключевых слов языка Java, включая основные, контекстные и зарезервированные слова.Основы языка Java
Что требуется знать перед началом изучения языка программирования Java
Рекомендации по разработке на Java
История языка Java
Экосистема Java-приложений
Структура и сборки Java-проектов
Справочник по конфигурациям в Java
Первая программа на Java
Простые приложения на Java
Отладка Java-кода в IDE
Синтаксис и пунктуация в Java
Ключевые слова в Java