Зачем и нужно ли выключать csrf в SpringSecurity при использовании авторизации через custom токен
Смотрел обучающее видео по авторизации и аутентификации по токену, и там в методе, который подключает фильтры есть запись http.csrf().disable() . Зачем мы отключаем csrf-защиту, человек не пояснил? Вот полный класс для лучшего понятия, о чем я:
@Configuration @RequiredArgsConstructor public class SecurityConfig < private final JwtTokenProvider jwtTokenProvider; @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception < http .httpBasic().disable() .csrf().disable() .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) .and() .authorizeHttpRequests(authz -> < try < authz .requestMatchers("/api/auth/**").permitAll() .requestMatchers("/api/admin/sensors/**").hasAuthority("ROLE_ADMIN") .requestMatchers("/api/sensors/**").hasAnyAuthority("ROLE_ADMIN", "ROLE_USER") .anyRequest().authenticated() .and() .apply(new JwtConfigurer(jwtTokenProvider)); >catch (Exception e) < throw new RuntimeException(e); >> ); return http.build(); > >
Отслеживать
задан 15 янв 2023 в 23:52
0
Сортировка: Сброс на вариант по умолчанию
Знаете кого-то, кто может ответить? Поделитесь ссылкой на этот вопрос по почте, через Твиттер или Facebook.
- spring-security
- csrf
Spring Security 4 + CSRF (добавление в Spring проект защиты от межсайтовой подделки запроса)

Здравствуйте!
Современное веб приложение считается уязвимым, если в нем отсутствует защита от Межсайтовой подделки запроса (CSRF).
В Spring Security 4.x она включена по умолчанию, поэтому при миграции с Spring Security 3.x на 4.x ее надо либо отключить
либо, правильнее и зачетнее, добавить в проект.
Собственно, сделал это в 10-минутном видео:
Ниже приведу основные моменты внедрения CSRF в проект:
- Использовать правильные HTTP запросы: по умолчанию CSRF защита отсутствует для запросов GET, HEAD, TRACE, OPTIONS. Это в частности означает, что для logout, если мы не хотим, чтобы злоумышленный сайт мог разлогинить пользователя, авторизованного в нашем приложении, требуется запрос POST.
- Во всех формах, где есть submit, добавить скрытое поле name=_csrf со значением csrfToken. Проще всего это сделать через Spring’s form tag library, который, кроме биндинга и валидации, при включенном csrf подставит в форму требуемое скрытое поле.
var token = $("meta[name='_csrf']").attr("content"); var header = $("meta[name='_csrf_header']").attr("content"); $(document).ajaxSend(function(e, xhr, options) < xhr.setRequestHeader(header, token); >);
@RestController @RequestMapping(value = AdminRestController.REST_URL, consumes = MediaType.APPLICATION_JSON_VALUE)
Ну и напоследок несколько ссылок на тему:
- Spring Security CSRF Protection
- Are JSON web services vulnerable to CSRF attacks
- Правило ограничения домена (SOP)
- Cross-origin resource sharing (CORS)
CSRF-токен
В этой статье рассмотрим, что такое Сross-Site Request Forgery и как включить в Spring Boot приложение CSRF-токен — защиту от этого мошенничества. Назвать этот токен можно было бы «анти-CSRF-токен».
Same Origin Policy и CSRF (cross-site request forgery)
Обычно запросы, сделанные в браузере с одного домена на другой, не проходят, поскольку браузер придерживается Same Origin Policy. Это политика безопасности, защищающая одни сайты от других.
Например, пусть пользователь случайно заходит на домен evil.com (мошеннический сайт) и щелкает там яркую кнопку, которая выполняет либо PUT-запрос, либо DELETE-запрос на bank.com. И так случайно получилось, что этот пользователь зарегистрирован на bank.com и в браузере хранятся куки к нему. Благодаря политике безопасности браузера, ничего плохого не случится. Потому что браузер сначала вышлет так называемый «preflight», то есть предварительный OPTIONS-запрос на bank.com с заголовком
Origin: evil.com
и затем отправит за ним настоящий PUT/DELETE-запрос, но только в том случае, если в ответе пришло разрешение на отправку запросов от evil.com. В противном случае в метод PUT/DELETE банковского сайта мы даже не попадем.
То есть предварительный запрос спрашивает у одного домена разрешение на отправку данных с другого. И чтобы bank.com (получатель запросов) отправил положительный ответ, программист bank.com должен знать домен evil.com (отправителя запросов). Тогда программист делает так, чтобы согласно спецификации CORS bank.com отправлял в ответе в заголовке Access-Control-Allow-Origin адрес evil.com. Это означает буквально «сайту evil.com можно ко мне обращаться». Как настроить CORS в Spring Boot читайте тут. CORS — это своего рода послабление Same Origin Policy. В данной статье CORS нет.
Но есть запросы, которые отправляются сразу, без предварительного запроса, так называемые simple requests. Это GET, HEAD, POST с определенным Content-Type. В частности, POST-запросы с формы. Такой запрос сразу идет в контроллер. А учитывая, что куки браузер отправляет автоматически, запрос попадет в защищенный контроллер и выполнит действие на банковском сайте. Хотя ответ получить и распарсить нельзя, действие будет выполнено.
Ниже рассмотрим, как это происходит. В примере одно приложение на одном домене делает POST-запрос на другой домен, где работает второе приложение. Рассмотрим, как защититься от таких запросов с помощью CSRF-токена.
Пример жульничества
Создадим два приложения на Spring Boot:
- мишень для атаки, «банковское» приложение на порту 8080
- и мошеннический сайт на порту 8081
Поскольку в примере мы будем делать запрос на «другой домен», пропишем для localhost:8080 новое имя в файле hosts:
C:\Windows\System32\drivers\etc\hosts
А именно, добавим в файл hosts строку:
127.0.0.1 bank-server
Теперь к приложению-мишени будем обращаться по адресу http://bank-server:8080/..вместо http://localhost:8080..
Приложение-мишень
Итак, пусть в нашем приложении есть контроллер и форма, с которой что-то добавляется:

@Controller public class DocumentController < @PostMapping("/add") public String add(Document document, Model model) < System.out.println(document.getId()+" "+document.getText()+" added"); model.addAttribute("document", document); model.addAttribute("message", "добавлено"); System.out.println("PostMapping /add"); return "add"; >@GetMapping("/add") public String get() < System.out.println("GetMapping /add"); return "add"; >@GetMapping("/") public String main() < return "redirect:/add"; >>
Форма на Thymeleaf выглядит так:
При этом адрес http://bank-server:8080/add защищен, доступ к нему возможен только благодаря куки JSESSIONID после входа с помощью формы логина.
В приложении задан единственный in-memory пользователь с именем user и паролем user:
@EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter < @Bean public PasswordEncoder passwordEncoder() < return NoOpPasswordEncoder.getInstance(); >@Override public void configure(AuthenticationManagerBuilder auth) throws Exception < auth.inMemoryAuthentication() .withUser("user") .password("user") .authorities("ROLE_USER"); >@Override protected void configure(HttpSecurity http) throws Exception < http.authorizeRequests() .anyRequest().authenticated() .and().formLogin(); http.csrf().disable(); >>
Выше прописано, что все запросы доступны только аутентифицированным пользователям (в том числе наша форма — ее получение по адресу /add методом GET и отправка методом POST). Форма находится в шаблоне add.html
Проверку CSRF-токена мы отключили выше отдельной строкой:
http.csrf().disable();
Это сделано для того, чтобы продемонстрировать атаку с помощью второго приложения ниже. А затем включить CSRF-токен обратно. (По умолчанию он и так включен, просто нужно не забывать добавлять его и на форму, что будет в показано самом конце).
Мошенническое приложение
Второе приложение совсем простое, оно состоит из одного view с кнопкой атаки POST (полный код тут):

.Мошенническая кнопка: