Csrf disable spring что это
Перейти к содержимому

Csrf disable spring что это

  • автор:

Spring Security 4 + CSRF (добавление в Spring проект защиты от межсайтовой подделки запроса)

Здравствуйте!
Современное веб приложение считается уязвимым, если в нем отсутствует защита от Межсайтовой подделки запроса (CSRF).
В Spring Security 4.x она включена по умолчанию, поэтому при миграции с Spring Security 3.x на 4.x ее надо либо отключить

либо, правильнее и зачетнее, добавить в проект.

Собственно, сделал это в 10-минутном видео:

Ниже приведу основные моменты внедрения CSRF в проект:

  1. Использовать правильные HTTP запросы: по умолчанию CSRF защита отсутствует для запросов GET, HEAD, TRACE, OPTIONS. Это в частности означает, что для logout, если мы не хотим, чтобы злоумышленный сайт мог разлогинить пользователя, авторизованного в нашем приложении, требуется запрос POST.
  2. Во всех формах, где есть 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)

Как защитить Spring приложение, отключив CSRF-токен?

Всем доброго времени суток.
Я пишу Spring-boot (security) приложение и хочу использовать все инструменты веб-разработки. А именно: iframe и упрощённые ajax запросы. Во время разработки отключаю CSRF, добавляя в настройки http.csrf().disable() По хорошему CORS запросы настраиваются, но в некоторых случаях настроек мало. Например, когда нужно сделать sharing через iframe (пример: YouTube, Twitter и др.). И я решаю эту задачу путём банального добавления Principal в параметры каждого контроллера.

@GetMapping("/page") public @ResponseBody void page(Principal principal) < if(principal==null) return; String email = principal.getName(); Person pers = service.getUserByLogin(email); //some code. >

Вся логика приложения строится на том, что каждый запрос либо авторизованный, либо нет. Разумеется, у каждого пользователя свои связные данные (Linked data) и он не может получить доступ к личной информации других пользователей. Вопрос: На сколько удовлетворяет такое решение Same Origin Policy и на сколько это безопасно?

  • Вопрос задан 04 дек. 2023
  • 179 просмотров

Комментировать
Решения вопроса 0
Ответы на вопрос 2
calculator212 @calculator212
Ответ написан 05 дек. 2023
Нравится 2 2 комментария
My1Name @My1Name Автор вопроса

По второй ссылке хорошо описана ситуация и, в данном случае, мне необходимо позаботиться о «кликджекинге».

Когда сайт загружается в IFrame, все его кнопки становятся доступными и на сайте потенциального злоумышленника; любой щелчок считается действительным и для моего приложения. Это может быть фишинг и всё что угодно.

Возникает другой вопрос: Если добавить проверку референс getRequestURL(); в методы контролёра, такой запрос через iframe будет считаться внешним или локальным? Как узнать URL запроса если страница во фрейме?

calculator212 @calculator212

позаботиться о «кликджекинге»

Вроде достаточно настроить X-Frame-Options: тут
хз насколько актуально но вроде это просто делается в спринге

My1Name @My1Name Автор вопроса

Учитывая тот факт, что у меня не банковское приложение и финансовых рисков особо никаких нет, я не вижу причин запрещать пользователям встраивать личные страницы (или др. страницы сайта) в iframe. Главная задача в таком случае: ͟з͟а͟п͟р͟е͟т͟и͟т͟ь͟ ͟а͟в͟т͟о͟р͟и͟з͟и͟р͟о͟в͟а͟н͟н͟ы͟е͟ ͟з͟а͟п͟р͟о͟с͟ы͟. Для этого я разместил в шапку (в header на всех страницах сайта) незамысловатый скрипт:

const currentUrl = document.referrer; $.get('ajax/index', );

document.referrer — возвращает URL родительской страницы (которая загрузила iframe). Это работает, даже если родительский документ и iframe находятся на разных доменах. Как только начинается загрузка страницы, currentUrl отправляется в контроллер:

private @ResponseBody void checkReferrer(Principal principal, HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException < String currentUrl = req.getParameter("ref"); currentUrl = currentUrl.substring(currentUrl.indexOf("/")+2); String localName = req.getServerName(); if (principal!=null && !currentUrl.startsWith(localName)) < req.getSession().invalidate(); req.logout(); Cookie [] cookies = req.getCookies(); if(cookies!=null) < for(Cookie c : cookies) < c.setValue(""); c.setPath("/"); c.setMaxAge(0); resp.addCookie(c); >> > >

Контроллер проверяет переданный URL и сравнивает его с именем сервера. Далее, если переданный адрес не включает в себя имя сервера и это ͟а͟в͟т͟о͟р͟и͟з͟и͟р͟о͟в͟а͟н͟н͟ы͟й͟ ͟з͟а͟п͟р͟о͟с͟, то происходит выход с системы и удаление всех куки. В настройках Spring-Security:

http.csrf() .disable().and() . frameOptions().sameOrigin();

Политика Same-Origin предотвращает доступ внешним скриптам к странице встроенной в iframe. А при отключении скриптов, любые запросы будут происходить от имени пользователя. То есть, програмно можно получить доступ только к своему аккаунту и только через главный вход (через iframe вход не получится). А если я что-то не учёл — критика в комментариях приветствуется.

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 (полный код тут):

Сайт жуликов

 . 

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

Кнопка отправляет форму со скрытыми полями: и text=«document». Если в браузере мы залогинены в приложении http://bank-server:8080 и откроем мошеннический сайт localhost:8081 с вышеприведенной кнопкой и щелкнем ее, то сохраненный куки JSESSIONID отправляется тоже, и мы попадаем в защищенный метод add() контроллера DocumentController банковского сайта. Документ добавляется.

Защита с помощью CSRF-токена

Чтобы защититься от таких запросов, нужно включить CSRF-токен, то есть убрать строку отключения, которую мы добавили выше:

// http.csrf().disable();

Теперь когда пользователь логинится на сайт http://bank-server:8080, ему выделяется специальный CSRF-токен. Он хранится в сессии и должен отправляться как скрытое поле со всех форм (также он должен прилагаться в XMLHttpRequest-запросах PUT, DELETE, POST — это для JavaScript). Выше мы показали только одну атаку, но при определенных настройках Spring MVC в определенных браузерах возможны и более сложные атаки. И хотя браузеры становятся все более безопасными, как и сам Spring MVC, все равно Spring Security имеет вот такое требование и для PUT, и для DELETE-запросов, хотя для них существуют «preflight» запросы от браузера. Но эти настройки CSRF-токена можно и поменять — убрать некоторые методы или некоторые url — сделать так, чтобы для них не требовался токен.

Итак, токен в POST-запросах сейчас требуется. Если оставить все как есть, то наше собственное банковское приложение не заработает — при попытке отправить форму получим 403. Надо сделать так, чтобы выданный CSRF-токен отправлялся. Для этого добавим его как скрытое поле на форму в наш Thymeleaf-шаблон:

Все, теперь и наше приложение работает, и с чужого сайта форму отправить нельзя, потому что мошенники не знают CSRF-токен. В отличие от JSESSIONID, он не хранится в куки браузера и не отправляется автоматически при запросах на банковский сайт.

Итоги

Исходный код обоих приложений есть на GitHub.

Spring State Security, часть 1: защита CSRF без сохранения состояния

Сегодня, когда архитектура RESTful становится все более и более стандартной, возможно, стоит потратить некоторое время на переосмысление ваших текущих подходов к обеспечению безопасности. В этой небольшой серии постов в блоге мы рассмотрим несколько относительно новых способов решения проблем безопасности, связанных с сетью, без учета состояния. Эта первая запись о защите вашего сайта от подделки межсайтовых запросов (CSRF).

Резюме: Что такое подделка межсайтовых запросов?

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

Другой сайт может злоупотребить этим, если браузер отправляет (межсайтовый) запрос на сайт, подвергающийся атаке. Например, включение некоторого javascript для создания тега POST для http://siteunderattack.com/changepassword?pw=hacked приведет к тому, что браузер выполнит этот запрос, прикрепив к запросу любые (аутентификационные) файлы cookie, все еще активные для этого домена!

Несмотря на то, что политика единого источника (SOP) не разрешает вредоносному сайту доступ к какой-либо части ответа. Как видно из приведенного выше примера, вред уже нанесен, если запрошенный URL-адрес вызывает какие-либо побочные эффекты (изменения состояния) в фоновом режиме.

Общий подход

Обычно используемое решение состоит в том, чтобы ввести требование так называемого общего секретного CSRF-токена и сделать его известным клиенту как часть предыдущего ответа.
Затем клиент должен отправить его обратно на сервер для любых запросов с побочными эффектами. Это можно сделать либо непосредственно внутри формы в виде скрытого поля, либо в виде пользовательского HTTP-заголовка. В любом случае другие сайты не могут успешно генерировать запросы с включенным правильным CSRF-токеном, поскольку SOP предотвращает чтение ответов с сервера между сайтами. Проблема этого подхода заключается в том, что серверу необходимо запоминать значение каждого CSRF-токена для каждого пользователя в сеансе.

Подходы без гражданства

1. Переключитесь на полный и правильно разработанный REST API на основе JSON.

Политика единого происхождения допускает только HEAD / GET и POST для нескольких сайтов. POST могут быть только одним из следующих типов mime: application / x-www-form-urlencoded, multipart / form-data или text / plain. На самом деле нет JSON! Теперь, учитывая, что GET никогда не должны вызывать побочные эффекты в каком-либо должным образом спроектированном API на основе HTTP, это позволяет вам просто запретить любые не-JSON POST / PUT / DELETE, и все в порядке. Для сценария с загрузкой файлов (multipart / form-data) все еще необходима явная защита CSRF.

2. Проверьте заголовок HTTP Referer.

Подход, описанный выше, может быть дополнительно уточнен путем проверки наличия и содержимого заголовка Referer для сценариев, которые все еще восприимчивы, например, POST-данных multipart / form-data. Этот заголовок используется браузерами, чтобы указать, какая именно страница (URL) инициировала запрос. Это можно легко использовать для проверки ожидаемого домена для сайта. Обратите внимание, что при выборе такой проверки вы никогда не должны разрешать запросы без присутствующего заголовка.

3. Клиентские сгенерированные CSRF-токены.

Пусть клиенты сгенерируют и отправят одно и то же уникальное секретное значение как в Cookie, так и в пользовательском HTTP-заголовке Учитывая, что веб-сайту разрешено только чтение / запись Cookie для своего собственного домена, только реальный сайт может отправлять одинаковые значения в обоих заголовках. Используя этот подход, все, что должен сделать ваш сервер, – это проверить, равны ли оба значения без сохранения состояния для каждого запроса!

Реализация

Сосредоточив внимание на третьем подходе к явной, но без сохранения состояния безопасности на основе токенов CSRF, давайте посмотрим, как это выглядит в коде с использованием Spring Boot и Spring Security.

В Spring Boot вы получаете хорошие настройки безопасности по умолчанию, которые вы можете настроить, используя свой собственный конфигурационный адаптер. В этом случае все, что нужно, это отключить поведение csrf по умолчанию и добавить собственный StatelessCSRFFilter:

Настроить защиту CSRF

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *