Logo Craft Homelab Docs Контакты Telegram
CSRF и CORS в Spring Security: защита cookie-сессий и API Трендовые github проекты в нашем телеграм канале. Подпишись →
5 августа 2026 г.

Настраиваем защиту браузерного клиента в Spring Security

Безопасность браузерного приложения зависит не только от аутентификации. Сервер может корректно проверять пользователя по сессии или токену, однако браузер автоматически прикладывает cookie к части запросов, а политики доступа между origins определяют, какой JavaScript сможет прочитать ответ API. Эти два слоя закрывают разные риски: CSRF контролирует нежелательные действия от имени уже вошедшего пользователя, CORS ограничивает чтение ответов чужими сайтами.

Для Spring-приложения полезно сначала определить модель аутентификации и список реальных доменов фронтенда. После этого параметры CSRF и CORS становятся частью явной конфигурации, которую проще проверить при деплое.

Что происходит при CSRF

Cross-Site Request Forgery возникает, когда пользователь уже авторизован на сайте, а сторонняя страница заставляет его браузер отправить запрос на этот сайт. Например, скрытая форма или скрипт может обратиться к банковскому endpoint. Браузер распознаёт домен назначения и автоматически добавляет сохранённые для него cookie сессии. Для сервера запрос выглядит как действие авторизованного пользователя.

CSRF-защита добавляет в запрос секрет, который злоумышленник со стороннего origin не может прочитать и повторить. Spring Security сопоставляет это значение с тем, которое ожидает сервер. При отсутствии или несовпадении токена изменяющий запрос получает ответ 403 Forbidden.

Риск определяется способом передачи учётных данных:

  • При Bearer JWT, который фронтенд хранит вне cookie и передаёт в заголовке Authorization, браузер не приложит токен автоматически к запросу со сторонней страницы. В этой схеме CSRF-защита обычно не требуется.
  • При сессии и cookie браузер отправляет JSESSIONID сам. Запросы POST, PUT и DELETE требуют дополнительной проверки CSRF-токена.

Отключать CSRF стоит только после проверки этой модели. Для API на cookie-сессиях отключённая защита делает состояние пользователя доступным для подделки запросов со сторонних страниц.

CSRF-токен для REST API

В приложении с REST-фронтендом токен удобно хранить в cookie и передавать обратно отдельным заголовком. Spring Security предоставляет для этого CookieCsrfTokenRepository:

http.csrf(csrf -> csrf
    .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
);

При первом обращении сервер создаёт случайный CSRF-токен и помещает его в cookie XSRF-TOKEN. Клиентский код читает значение cookie и добавляет его в заголовок X-XSRF-TOKEN для запросов, которые меняют данные. В запросе одновременно приходят cookie и заголовок; Spring Security сравнивает их значения.

withHttpOnlyFalse() здесь нужен именно фронтенду: JavaScript должен получить токен из cookie, чтобы сформировать заголовок. Сессионную cookie это не касается — для неё флаг HttpOnly по-прежнему нужен. Доступ к XSRF-TOKEN со страницы другого сайта ограничивает Same Origin Policy, поэтому сторонний скрипт не узнает значение, которое требуется серверу.

Типовая последовательность выглядит так:

  1. Сервер отвечает с JSESSIONID и XSRF-TOKEN.
  2. Фронтенд отправляет POST, PUT или DELETE и добавляет X-XSRF-TOKEN.
  3. Браузер добавляет cookie нужного домена.
  4. Spring Security сравнивает токен из cookie со значением заголовка и разрешает запрос только при совпадении.

CORS задаёт границы для чтения API

CORS расшифровывается как Cross-Origin Resource Sharing. Это набор правил, которые сервер отправляет браузеру: они определяют, какие чужие origins могут читать ответы API. Сам механизм не заменяет аутентификацию и CSRF-защиту. Его задача — не дать JavaScript с произвольного сайта получить доступ к данным ответа.

Проблема появляется при чрезмерно широких настройках. Если сервер отражает любой Origin в Access-Control-Allow-Origin и одновременно разрешает передачу cookie через Access-Control-Allow-Credentials: true, браузер сможет отдать ответ JavaScript на недоверенном сайте. Для API с пользовательскими данными список origins должен быть явным.

В Spring Security конфигурацию можно зарегистрировать как bean и подключить к цепочке фильтров:

@Bean
public CorsConfigurationSource corsConfigurationSource() {
    CorsConfiguration config = new CorsConfiguration();
    config.setAllowedOrigins(List.of(
        "http://localhost:3030",
        "https://myapp.com"
    ));
    config.setAllowedMethods(List.of(
        "GET", "POST", "PUT", "DELETE", "OPTIONS"
    ));
    config.setAllowedHeaders(List.of(
        "Authorization", "Content-Type"
    ));
    config.setAllowCredentials(true);
    config.setMaxAge(3600L);

    UrlBasedCorsConfigurationSource source =
        new UrlBasedCorsConfigurationSource();
    source.registerCorsConfiguration("/**", config);
    return source;
}

Затем конфигурация включается в SecurityFilterChain:

http.cors(cors -> cors
    .configurationSource(corsConfigurationSource())
);

setAllowedOrigins перечисляет домены фронтенда. setAllowedMethods и setAllowedHeaders ограничивают форму запросов, которую API готов принять. setMaxAge определяет время кэширования результата предварительной проверки OPTIONS в браузере.

Credentials требуют конкретных origins

Параметр setAllowCredentials(true) разрешает браузеру отправлять cookie и другие учётные данные в cross-origin запросах. Вместе с ним нельзя использовать wildcard "*" для разрешённых origins: браузер заблокирует такую комбинацию. Поэтому в конфигурации с credentials перечисляют конкретные адреса, включая локальный адрес разработки и домен production-фронтенда.

Этот список стоит пересматривать вместе с окружениями. Временный preview-домен, старый административный интерфейс или слишком широкая маска расширяют круг сайтов, которым браузер разрешит читать ответы с учётными данными пользователя.

Проверка конфигурации перед релизом

Для cookie-сессий проверьте, что изменяющие endpoint’ы принимают CSRF-токен и возвращают 403 без него. Для JWT убедитесь, что токен не записывается в cookie и клиент добавляет его только в Authorization. Для CORS сопоставьте разрешённые origins с фактически развёрнутыми фронтендами, оставьте минимальный набор методов и заголовков, а также отдельно протестируйте запросы с credentials.

Такое разделение проверок помогает сохранить предсказуемое поведение API: сессия подтверждает пользователя, CSRF-токен подтверждает намерение браузерного клиента, а CORS не открывает ответы приложения посторонним origins.