Подделка межсайтовых запросов (CSRF)
Spring предусматривает комплексные средства поддержки для защиты от подделки межсайтовых запросов (CSRF). В следующих разделах мы рассмотрим:
-
>Что такое CSRF-атака?
-
Защита от CSRF-атак
-
Рекомендации по поводу CSRF
Что такое CSRF-атака?
Лучше всего можно понять, что такое CSRF-атака, рассмотрев конкретный пример.
Предположим, что на сайте вашего банка есть форма, позволяющая перевести деньги от текущего пользователя, вошедшего в систему, на другой банковский счет. Например, форма перевода может выглядеть следующим образом:
<form method="post"
action="/transfer">
<input type="text"
name="amount"/>
<input type="text"
name="routingNumber"/>
<input type="text"
name="account"/>
<input type="submit"
value="Transfer"/>
</form>
Соответствующий HTTP-запрос может выглядеть следующим образом:
POST /transfer HTTP/1.1
Host: bank.example.com
Cookie: JSESSIONID=randomid
Content-Type: application/x-www-form-urlencoded
amount=100.00&routingNumber=1234&account=9876
Теперь представьте, что вы авторизовались на сайте своего банка, а затем, не выходя из системы, посетили сайт злоумышленников. Веб-сайт злоумышленников содержит HTML-страницу со следующей формой:
<form method="post"
action="https://bank.example.com/transfer">
<input type="hidden"
name="amount"
value="100.00"/>
<input type="hidden"
name="routingNumber"
value="evilsRoutingNumber"/>
<input type="hidden"
name="account"
value="evilsAccountNumber"/>
<input type="submit"
value="Win Money!"/>
</form>
Вам нравится выигрывать деньги, поэтому вы нажимаете на кнопку отправки. При этом вы непреднамеренно передали 100 долларов злоумышленнику. Это происходит потому, что, хотя сайт злоумышленников и не видит ваши файлы cookie, файлы cookie, связанные с вашим банком, все равно отправляются вместе с запросом.
Хуже всего то, что весь этот процесс можно было бы автоматизировать с помощью JavaScript. Это означает, что вам даже не нужно было нажимать на кнопку. Более того, это может так же легко произойти при посещении добросовестного сайта, который стал жертвой XSS-атаки. Как же защитить пользователей от таких атак?
Защита от CSRF-атак
Причина, по которой возможно осуществлять CSRF-атаки, заключается в том, что HTTP-запрос с сайта жертвы и запрос с сайта злоумышленника абсолютно одинаковы. Это значит, что нет возможности отклонять запросы, поступающие с сайта злоумышленников, и разрешать запросы, поступающие с сайта банка. Для защиты от CSRF-атак нам нужно убедиться, что в запросе есть что-то, что сайт злоумышленников неспособен передавать, чтобы мы могли отличить эти два запроса.
Spring предусматривает два механизма для защиты от CSRF-атак:
-
Шаблон токена синхронизатора
-
Задание атрибута SameSite в файле cookie в рамках сессии
Оба вариант защиты требуют, чтобы безопасные методы были идемпотентными
Безопасные методы должны быть идемпотентными
Для того чтобы сработал любой из вариантов защиты от CSRF, приложение должно удостовериться, что "безопасные" HTTP-методы являются идемпотентными. Это значит, что запросы с HTTP-методом GET
, HEAD
, OPTIONS
и TRACE
не должны изменять состояние приложения.
Шаблон токена синхронизатора
Преобладающим и наиболее полным способом защиты от CSRF-атак является использование шаблона синхронизатора токенов. Это решение заключается в том, что каждый HTTP-запрос будет требовать, чтобы в дополнение к нашему сеансовому файлу cookie в HTTP-запросе присутствовало безопасное случайно сгенерированное значение, называемое CSRF-токеном.
После отправки HTTP-запроса, сервер должен осуществить поиск предполагаемого CSRF-токена и сравнить его с фактическим CSRF-токеном в HTTP-запросе. Если значения не совпадут, HTTP-запрос должен быть отклонен.
Ключевым моментом в этой работе является то, что фактический CSRF-токен должен находиться в той части HTTP-запроса, которая не добавляется браузером автоматически. Например, требование ввести фактический CSRF-токен в HTTP-параметр или HTTP-заголовок защитит от CSRF-атак. Запрос фактического CSRF-токена в файле cookie не сработает, поскольку файлы cookie автоматически добавляются браузером в HTTP-запрос.
Мы можем сделать ожидаемые события менее строгими и требовать только фактический CSRF-токен для каждого HTTP-запроса, который обновляет состояние приложения. Чтобы это сработало, наше приложение должно удостовериться, что безопасные HTTP-методы являются идемпотентными. Это повысит удобство использования, поскольку нам требуется разрешить ссылки на наш сайт с помощью ссылок с внешних сайтов. Кроме того, нам не нужно добавлять случайный токе в HTTP-метод GET, поскольку это может привести к утечке токенов.
Давайте посмотрим, как изменится наш пример при использовании шаблона токена синхронизатора. Предположим, что фактический CSRF-токен должен находиться в HTTP-параметре с именем _csrf
. Форма перевода в нашем приложении будет выглядеть следующим образом:
<form method="post"
action="/transfer">
<input type="hidden"
name="_csrf"
value="4bfd1575-3ad1-4d21-96c7-4ef2d9f86721"/>
<input type="text"
name="amount"/>
<input type="text"
name="routingNumber"/>
<input type="hidden"
name="account"/>
<input type="submit"
value="Transfer"/>
</form>
Теперь форма содержит скрытые входные данные со значением CSRF-токена. Внешние сайты не смогут прочитать CSRF-токен, поскольку та же политика по поводу источников гарантирует, что сайт злоумышленников не сможет прочитать ответ.
Соответствующий HTTP-запрос на перевод денег будет выглядеть следующим образом:
POST /transfer HTTP/1.1
Host: bank.example.com
Cookie: JSESSIONID=randomid
Content-Type: application/x-www-form-urlencoded
amount=100.00&routingNumber=1234&account=9876&_csrf=4bfd1575-3ad1-4d21-96c7-4ef2d9f86721
Вы можете заметить, что HTTP-запрос теперь содержит параметр _csrf
с безопасным случайным значением. Сайт злоумышленников не сможет передать правильное значение для параметра _csrf
(которое должно быть явным образом передано на сайте злоумышленников), а перевод завершится ошибкой, когда сервер сравнит фактический CSRF-токен с ожидаемым CSRF-токеном.
Атрибут SameSite
Находящийся в стадии становления способ защиты от CSRF-атак заключается в указании атрибута SameSite для файлов cookie. Сервер может указать атрибут SameSite
при настройке cookie, чтобы обозначить, что cookie не следует отправлять при поступлении с внешних сайтов.
Spring Security не управляет напрямую созданием cookie для сессии, поэтому он не предусматривает поддержку атрибута SameSite. Spring Session предусматривает поддержку атрибута SameSite
в приложениях на основе сервлетов. CookieWebSessionIdResolver в Spring Framework обеспечивает поддержку атрибута SameSite
в приложениях на базе WebFlux.
Пример HTTP-заголовка ответа с атрибутом SameSite
может выглядеть следующим образом:
Set-Cookie: JSESSIONID=randomid; Domain=bank.example.com; Secure; HttpOnly; SameSite=Lax
Допустимыми значениями для атрибута SameSite
являются:
-
Strict
– при указании этого параметра любой запрос, приходящий с того же сайта, будет включать cookie. В противном случае cookie не будет включен в HTTP-запрос. -
Lax
– если заданные cookies будут отправлены при поступлении с того же сайта или если запрос поступает из навигации на верхнем уровне, а метод является идемпотентным. В противном случае файл cookie не будет добавлен в HTTP-запрос.
Давайте посмотрим, как наш пример можно защитить с помощью атрибута SameSite
. Банковское приложение может защититься от CSRF-атак, задав атрибут SameSite
в файле cookie для сессии.
При установке атрибута SameSite
для нашего сессионного файла cookie браузер будет продолжать отправлять файл cookie JSESSIONID
с запросами, поступающими с банковского сайта. Однако браузер больше не будет отправлять файл cookie JSESSIONID
с запросом на передачу данных, поступающим с веб-сайта злоумышленников. Поскольку сессия больше не значится в запросе на перевод, поступающем с сайта злоумышленников, приложение будет защищено от CSRF-атаки.
Существует несколько важных нюансов, о которых следует знать при использовании атрибута SameSite
для защиты от CSRF-атак.
Установка атрибута SameSite
в значение Strict
обеспечивает более надежную защиту, но может запутать пользователей. Рассмотрим пользователя, который заходит на сайт социальной сети, расположенный по адресу social.example.com. Пользователь получает электронное письмо на адрес email.example.org, в котором содержится ссылка на сайт социальной сети. Если пользователь нажимает на ссылку, он вполне обоснованно ожидает, что будет аутентифицирован на сайте социальной сети. Однако если атрибут SameSite
имеет значение Strict
, файл cookie не будет отправлен, а пользователь не будет аутентифицирован.
Мы могли бы улучшить защиту и удобство использования механизма защиты от CSRF-атак с использованием SameSite
, реализовав gh-7537.
Еще один очевидный нюанс: чтобы атрибут SameSite
защищал пользователей, браузер должен предусматривать поддержку атрибута SameSite
. Большинство современных браузеров поддерживают атрибут SameSite. Однако старыми браузерами, которые все еще находящиеся в обиходе, такая поддержка может быть не предусмотрена.
По этой причине обычно рекомендуется использовать атрибут SameSite
в качестве глубокоэшелонированной защиты, а не как единственный механизм защиты от CSRF-атак.
Случаи использования защиты от CSRF
Когда следует использовать защиту от CSRF? Мы рекомендуем использовать защиту CSRF для любого запроса, который может быть обработан браузером, используемым обычными пользователями. Если вы создаете сервис, который будут использовать исключительно небраузерные клиенты, то, скорее всего, вам понадобится отключить защиту от CSRF.
Защита от CSRF и формат JSON
Частый вопрос: "Нужно ли мне защищать JSON-запросы, выполняемые javascript?". Краткий ответ: "Зависит от ситуации". Однако следует проявлять бдительность, поскольку существуют CSRF-эксплойты, которые могут повлиять на JSON-запросы. Например, злоумышленник может осуществить CSRF-атаку с помощью JSON, используя следующую форму:
<form action="https://bank.example.com/transfer" method="post" enctype="text/plain">
<input name='{"amount":100,"routingNumber":"evilsRoutingNumber","account":"evilsAccountNumber", "ignore_me":"' value='test"}' type='hidden'>
<input type="submit"
value="Win Money!"/>
</form>
В результате будет получена следующая структура JSON
{ "amount": 100,
"routingNumber": "evilsRoutingNumber",
"account": "evilsAccountNumber",
"ignore_me": "=test"
}
Если бы приложение не валидировало Content-Type, то оно было бы подвержено этому эксплойту. В зависимости от конфигурации, приложение Spring MVC, которое проверяет Content-Type, все еще может быть подвергнуто действию эксплойта путем обновления суффикса URL-адреса таким образом, чтобы он заканчивался на .json
, как показано ниже:
<form action="https://bank.example.com/transfer.json" method="post" enctype="text/plain">
<input name='{"amount":100,"routingNumber":"evilsRoutingNumber","account":"evilsAccountNumber", "ignore_me":"' value='test"}' type='hidden'>
<input type="submit"
value="Win Money!"/>
</form>
CSRF и приложения для браузеров, не сохраняющие состояние
Что делать, если мое приложение не сохраняет состояние? Данные факт не говорит о том, что вы отлично защищены. Фактически, если пользователю не требуется выполнять какие-либо действия в веб-браузере для данного запроса, он, скорее всего, все равно будет уязвим для CSRF-атак.
Например, рассмотрим приложение, которое использует для аутентификации вместо JSESSIONID кастомный cookie, содержащий все состояние внутри него. При осуществлении CSRF-атаки кастомный файл cookie будет отправлен вместе с запросом тем же образом, что и файл cookie JSESSIONID из нашего предыдущего примера. Это приложение будет уязвимо для CSRF-атак.
Приложения, использующие базовую аутентификацию, также уязвимы к CSRF-атакам. Приложение уязвимо, поскольку браузер будет автоматически включать имя пользователя и пароль в любые запросы тем же способом, каким в нашем предыдущем примере был отправлен файл cookie JSESSIONID.
Рекомендации по поводу CSRF
При реализации защиты от CSRF-атак необходимо учитывать несколько особых нюансов.
Вход в систему
Для защиты от подделки запросов на вход в систему HTTP-запрос на вход должен быть защищен от CSRF-атак. Защита от подделки запросов на вход в систему необходима для того, чтобы злоумышленник не смог считать конфиденциальную информацию жертвы. Атака осуществляется следующим образом:
-
Пользователь-злоумышленник выполняет вход в систему посредством CSRF, используя учетные данные пользователя-злоумышленника. После этого жертва аутентифицируется как пользователь-злоумышленник.
-
Пользователь-злоумышленник обманом заставляет жертву посетить взломанный сайт и ввести конфиденциальную информацию.
-
Информация привязывается к учетной записи пользователя-злоумышленника, после чего он может войти в систему со своими учетными данными и просмотреть конфиденциальную информацию жертвы.
Возможное осложнение в обеспечении защиты HTTP-запросов на вход в систему от CSRF-атак заключается в том, что пользователь может столкнуться с временем ожидания сессии, в результате чего запрос будет отклонен. Время ожидания сессии вызовет удивление у пользователей, которые не ожидали, что для входа в систему им понадобится сессия.
Выход из системы
Для защиты от подделки запросов на выход из системы, HTTP-запрос на выход из системы должен быть защищен от CSRF-атак. Защита от подделки запросов на выход из системы необходима для того, чтобы злоумышленник не смог считать конфиденциальную информацию жертвы. Более подробную информацию об атаке можно найти в этом блоге.
Возможное осложнение в обеспечении защиты HTTP-запросов на выход из системы от CSRF-атак заключается в том, что пользователь может столкнуться с временем ожидания сессии, в результате чего запрос будет отклонен. Время ожидания сессии вызовет удивление у пользователей, которые не ожидали, что для выхода из системы им понадобится сессия.
CSRF и время ожидания сессий
Чаще всего ожидаемый CSRF-токен хранится в сессии. Это значит, что как только сессия истечет, сервер не найдет ожидаемый CSRF-токен и отклонит HTTP-запрос. Существует несколько вариантов решения проблемы с временем ожидания, каждый из которых имеет свои недостатки.
-
Лучший способ смягчить последствия времени ожидания – использовать JavaScript для запроса CSRF-токена при отправке формы. Затем форма обновляется с помощью CSRF-токена и отправляется.
-
Другим вариантом является использование JavaScript, который сообщает пользователю, что срок действия его сессии истекает. Пользователь может нажать кнопку, чтобы продолжить и обновить сессию.
-
Наконец, ожидаемый CSRF-токен может храниться в файле cookie. Это позволяет ожидаемому CSRF-токену пережить сессию.
Кто-то может спросить, почему ожидаемый CSRF-токен не хранится в cookie по умолчанию. Это связано с известными эксплойтами, в которых заголовки (например, для указания cookies) могут устанавливаться другим доменом. По этой же причине Ruby on Rails больше не пропускает проверки CSRF при наличии заголовка X-Requested-With. Подробности о том, как выполнить эксплойт, смотрите в этой ветке webappsec.org. Другим недостатком является то, что, удалив состояние (то есть время ожидания), вы теряете возможность принудительно объявить недействительным токен, если он был скомпрометирован.
Многокомпонентность (загрузка файлов)
Защита многокомпонентных запросов (загрузка файлов) от CSRF-атак приводит к проблеме курицы и яйца. Для предотвращения CSRF-атаки необходимо прочитать тело HTTP-запроса, чтобы получить фактический CSRF-токен. Однако чтение тела означает, что файл будет загружен, а это в свою очередь значит, что внешний сайт сможет загрузить любой файл.
Существует два варианта использования защиты от CSRF с помощью multipart/form-data. Каждый вариант имеет свои компромиссы.
-
Размещение CSRF-токена в теле
-
Размещение CSRF-токена в URL-адресе
Прежде чем интегрировать CSRF-защиту Spring Security с загрузкой многокомпонентных файлов, сначала убедитесь, что сможете загружать файлы без CSRF-защиты.
Размещение CSRF-токена в теле
Первый вариант – добавить фактический CSRF-токен в тело запроса. Если поместить CSRF-токен в тело, тело будет прочитано до того, как будет выполнена авторизация. Это означает, что любой сможет размещать временные файлы на вашем сервере. Однако только авторизованные пользователи смогут отправить файл, который будет обработан вашим приложением. В целом, это рекомендуемый подход, поскольку загрузка временного файла должна оказывать незначительное влияние на большинство серверов.
Добавление CSRF-токена в URL-адрес
Если возможность загрузки временных файлов неавторизованными пользователями неприемлема, альтернативой может быть добавление ожидаемого CSRF-токена в качестве параметра запроса в атрибут действия в форме. Недостатком этого подхода является возможность утечки параметров запроса. В целом, наиболее оптимальным способом считается размещение конфиденциальных данных в теле или заголовках, что позволяет исключить их утечку. Дополнительную информацию можно найти в разделе 15.1.3 "RFC 2616: Кодирование конфиденциальной информации в URI".
HiddenHttpMethodFilter
В некоторых приложениях параметр формы может быть использован для переопределения HTTP-метода. Например, приведенная ниже форма может быть использована для обработки HTTP-метода как delete
, а не post
.
<form action="/process"
method="post">
<!-- ... -->
<input type="hidden"
name="_method"
value="delete"/>
</form>
Переопределение HTTP-метода происходит в фильтре. Этот фильтр должен быть установлен перед средствами поддержки Spring Security. Обратите внимание, что переопределение происходит только в post
, так что это вряд ли вызовет какие-либо реальные проблемы. Тем не менее, наиболее оптимальным является его размещение перед фильтрами Spring Security.
Безопасные заголовки HTTP-ответов
Существует множество заголовков для HTTP-ответов, которые можно использовать для повышения безопасности веб-приложений. Этот раздел посвящен различным заголовкам для HTTP-ответов, для которых в Spring Security предусмотрена явная поддержка. При необходимости Spring Security также можно сконфигурировать на использование кастомных заголовков.
Заголовки безопасности по умолчанию
Spring Security предусматривает стандартный набор связанных с безопасностью заголовков для HTTP-ответов, предназначенных для обеспечения безопасных параметров по умолчанию.
По умолчанию Spring Security содержит следующие заголовки:
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Content-Type-Options: nosniff
Strict-Transport-Security: max-age=31536000 ; includeSubDomains
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block
Если параметры по умолчанию не соответствуют вашим потребностям, вы можете легко удалить, изменить или добавить заголовки из этих параметров по умолчанию. Для получения дополнительной информации о каждом из этих заголовков обратитесь к соответствующим разделам:
-
Управление кэшем
-
Параметры типа содержимого
-
HTTP Strict Transport Security
-
Заголовок X-Frame-Options
-
Заголовок X-XSS-Protection
Управление кэшем
По умолчанию Spring Security отключает кэширование для защиты пользовательского содержимого.
Если пользователь авторизуется для просмотра конфиденциальной информации, а затем выходит из системы, нам нужно избежать ситуации, когда злоумышленник сможет нажать кнопку "Назад" и просмотреть конфиденциальную информацию. По умолчанию отправляются следующие заголовки управления кэшем:
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
Чтобы обеспечить защиту по умолчанию, Spring Security добавляет эти заголовки по умолчанию. Однако, если ваше приложение предусматривает свои собственные заголовки управления кэшем, Spring Security не будет применять свои. Это позволяет приложениям обеспечить кэширование статических ресурсов, таких как CSS и JavaScript.
Параметры типа содержимого
Исторически браузеры, включая Internet Explorer, предпринимали попытки угадать тип содержимого запроса с помощью сниффинга содержимого. Это позволило браузерам улучшить взаимодействие с пользователем путем угадывания типа содержимого для ресурсов, в которых тип содержимого не был задан. Например, если браузер примет файл JavaScript, для которого не задан тип содержимого, он сам сможет определить тип содержимого и запустить его.
В случае если разрешена загрузка содержимого, есть еще множество дополнительных мер, которые следует предпринять (например, отображать документ только в отдельном домене, убедиться, что установлен заголовок Content-Type, подвергнуть документ правке и т. д.). Однако эти меры выходят за рамки того, что предусматривает Spring Security. Также важно отметить, что при отключении сниффинга содержимого необходимо задать тип содержимого, чтобы все работало надлежащим образом.
Проблема со снифингом содержимого заключалась в том, что это позволяло злоумышленникам использовать полиглоты (т.е. файл, который допустимо использовать в качестве нескольких типов содержимого) для проведения XSS-атак. Например, некоторые сайты могут позволять пользователям отправить на сайт и просмотреть допустимый postscript-документ. Пользователь-злоумышленник может создать postscript-документ, который также является допустимым JavaScript-файлом, и осуществить с его помощью XSS-атаку.
В Spring Security сниффинг содержимого отключен по умолчанию путем добавления следующего заголовка к HTTP-ответам:
X-Content-Type-Options: nosniff
HTTP Strict Transport Security (HSTS)
Когда вы набираете веб-сайт своего банка, то вводите mybank.example.com или mybank.example.com? Если пропускать протокол https, то это создаст потенциальную уязвимость к атакам типа "человек посередине" (атака посредника). Даже если сайт выполняет переадресацию на mybank.example.com, злоумышленник может перехватить первоначальный HTTP-запрос и манипулировать ответом (например, переадресовать на mibank.example.com и украсть учетные данные).
Многие пользователи пропускают протокол https, поэтому был создан протокол HTTP Strict Transport Security (HSTS). После добавления mybank.example.com в качестве HSTS-хоста браузер может заранее понимать, что любой запрос к mybank.example.com должен быть интерпретирован как mybank.example.com. Это значительно снижает вероятность атаки типа "человек посередине".
В соответствии с RFC6797, HSTS-заголовок внедряется только в HTTPS-ответы. Для того чтобы браузер подтвердил заголовок, он должен сначала доверять центру сертификации, подписавшему SSL-сертификат, используемый для создания соединения (а не только SSL-сертификату).
Одним из способов пометить сайт как HSTS-хост является предварительная загрузка хоста в браузер. Второй способ – добавить в ответ заголовок Strict-Transport-Security
. Например, по умолчанию Spring Security добавляет следующий заголовок, который предписывает браузеру считать домен HSTS-хостом в течение года (в году примерно 31536000 секунд):
Strict-Transport-Security: max-age=31536000 ; includeSubDomains ; preload
Необязательная директива includeSubDomains
сообщает браузеру, что поддомены (например, secure.mybank.example.com) также должны считаться HSTS-доменами.
Необязательная директива preload
сообщает браузеру, что домен следует предварительно загружать в браузер как HSTS-домен. Более подробную информацию о предварительной загрузке HSTS можно найти на сайте hstspreload.org.
HTTP Public Key Pinning (HPKP)
В целях обеспечения пассивной работы Spring Security все еще предусматривает поддержку HPKP в сервлетных окружениях, но по причинам, перечисленным выше, команда по безопасности больше не может рекомендовать к использованию HPKP.
HTTP Public Key Pinning (HPKP) указывает веб-клиенту, какой открытый ключ использовать с определенным веб-сервером для предотвращения атак типа "человек посередине" (MITM) с поддельными сертификатами. При правильном использовании HPKP может добавлять дополнительные уровни защиты от скомпрометированных сертификатов. Однако из-за сложности HPKP многие специалисты больше не рекомендуют его использовать, а Chrome даже прекратил его поддерживать.
Для получения дополнительной информации о том, почему HPKP больше не рекомендуется использовать, читайте в статьях "Is HTTP Public Key Pinning Dead?" и "I’m giving up on HPKP".
Заголовок X-Frame-Options
Разрешение добавлять ваш сайт во фрейм может стать проблемой с точки зрения безопасности. Например, с помощью хитроумной CSS-стилизации можно обманом заставить пользователей нажать туда, куда они нажимать не собирались. Например, пользователь, вошедший в свой интернет-банк, может нажать кнопку, которая предоставит доступ другим пользователям. Этот вид атаки известен как кликджекинг.
Еще один современный подход к борьбе с кликджекингом – использование спецификации Content Security Policy (CSP).
Существует способов противостоять атакам типа кликджекинг. Например, для защиты устаревших браузеров от атак типа кликджекинг можно использовать код отключения фреймов. Хотя он и не идеален, код отключения фреймов – это лучшее, что можно предпринять в случае с устаревшими браузерами.
Более современный подход к решению проблемы кликджекинга заключается в использовании заголовка X-Frame-Options. По умолчанию Spring Security запрещает виузализировать страницы во встроенном фрейме (iframe) при использовании следующего заголовка:
X-Frame-Options: DENY
Заголовок X-XSS-Protection
Некоторые браузеры имеют встроенную поддержку для фильтрации отраженных XSS-атак. Это ни в коем случае не может считаться надежной защитой, но помогает при защите от XSS-атак.
Фильтрация чаще всего активирована по умолчанию, поэтому добавление заголовка обычно просто обеспечивает ее активацию и сообщает браузеру, что нужно делать при обнаружении XSS-атаки. Например, фильтр может попытаться изменить содержимое наименее агрессивным способом, чтобы визуализировать всё необходимое. Иногда такая замена может сама по себе стать XSS-уязвимостью. Вместо этого лучше заблокировать содержимое, а не пытаться его исправить. По умолчанию Spring Security блокирует содержимое, используя следующий заголовок:
X-XSS-Protection: 1; mode=block
Спецификация Content Security Policy (CSP)
Content Security Policy (CSP) – это механизм, который веб-приложения могут использовать для снижения риска возникновения уязвимостей к внедрению содержимого, таких как межсайтовый скриптинг (XSS). CSP – это декларативная политика, которая предоставляет авторам веб-приложений возможность объявлять и в конечном итоге сообщать клиенту (пользовательскому агенту) об источниках, из которых веб-приложение ожидает загрузку ресурсов.
Content Security Policy не решит все проблемы, связанные с уязвимостями к внедрению содержимого. Вместо этого CSP можно использовать для снижения вреда, наносимого атаками через внедрение содержимого. В рамках первой линии защиты авторы веб-приложений должны валидировать свои входные данные и кодировать выходные.
Веб-приложение сможет использовать CSP, если добавить в ответ один из следующих HTTP-заголовков:
-
Content-Security-Policy
-
Content-Security-Policy-Report-Only
Каждый из этих заголовков используется в качестве механизма реализации политики обеспечения безопасности для клиента. Политика обеспечения безопасности содержит набор директив политики обеспечения безопасности, каждая из которых отвечает за объявление ограничений для определенного представления ресурса.
Например, веб-приложение может объявить, что оно ожидает загрузки скриптов из определенных, доверенных источников, если добавить в ответ следующий заголовок:
Content-Security-Policy: script-src https://trustedscripts.example.com
Попытка загрузить скрипт из другого источника, отличного от того, что объявлен в директиве script-src
, будет заблокирована пользовательским агентом. Кроме того, если в политике обеспечения безопасности объявлена директива report-uri, то о нарушении пользовательский агент сообщит по объявленному URL-адресу.
Например, если веб-приложение нарушает объявленную политику обеспечения безопасности, следующий заголовок ответа сообщит пользовательскому агенту, что необходимо отправить отчеты о нарушении по URL-адресу, заданному в директиве report-uri
политики.
Content-Security-Policy: script-src https://trustedscripts.example.com; report-uri /csp-report-endpoint/
Сообщения о нарушениях представляют собой стандартные JSON-структуры, которые могут быть получены либо через собственный API веб-приложения, либо с помощью размещенного в открытом доступе сервиса передачи сообщений о нарушениях CSP, например, report-uri.com/.
Заголовок Content-Security-Policy-Report-Only
предоставляет авторам и администраторам веб-приложений возможность отслеживать политику обеспечения безопасности, а не навязывать ее. Этот заголовок обычно используется при проведении экспериментов и/или разработке политики безопасности для сайта. Если политика считается эффективной, ее можно применить, используя вместо этого поле заголовка Content-Security-Policy
.
Учитывая следующий заголовок ответа, политика объявляет, что скрипты могут быть загружены из одного из двух возможных источников.
Content-Security-Policy-Report-Only: script-src 'self' https://trustedscripts.example.com; report-uri /csp-report-endpoint/
Если сайт нарушит эту политику, попытавшись загрузить скрипт с сайта evil.com, пользовательский агент отправит отчет о нарушении по URL-адресу, заданному директивой report-uri, но при этом позволит нарушающему ресурсу загрузиться.
Применение спецификации Content Security Policy к веб-приложению зачастую является не такой уж простой задачей. Следующие ресурсы могут принести дополнительную пользу при разработке эффективной политики безопасности для вашего сайта.
Введение в Content Security Policy
Руководство по CSP – Mozilla Developer Network
Спецификация Referrer Policy
Referrer Policy – это механизм, который веб-приложения могут использовать для управления полем реферера, содержащим последнюю страницу, на которой находился пользователь.
Подход Spring Security заключается в использовании заголовка Referrer Policy, который предусматривает различные политики:
Referrer-Policy: same-origin
Заголовок ответа Referrer-Policy предписывает браузеру сообщить получателю источник, в котором ранее находился пользователь.
Спецификация Feature Policy
Feature Policy – это механизм, который позволяет веб-разработчикам выборочно активировать, деактивировать и изменять логику работы определенных API и веб-функций в браузере.
Feature-Policy: geolocation 'self'
С помощью Feature Policy разработчики могут выбирать набор "политик", которые браузер будет применять к определенным функциям, используемым на вашем сайте. Эти политики ограничивают доступ сайта к API или изменяют логику работы браузера по умолчанию для определенных функций.
Спецификация Permissions Policy
Permissions Policy – это механизм, который позволяет веб-разработчикам выборочно активировать, деактивировать и изменять логику работы определенных API и веб-функций в браузере.
Permissions-Policy: geolocation=(self)
С помощью Permissions Policy разработчики могут выбирать набор "политик", которые браузер будет применять к определенным функциям, используемым на вашем сайте. Эти политики ограничивают доступ сайта к API или изменяют логику работы браузера по умолчанию для определенных функций.
Заголовок Clear Site Data
Clear Site Data – это механизм, с помощью которого любые данные – cookies, локальное хранилище и тому подобное – можно удалить на стороне браузера, если HTTP-ответ будет содержать этот заголовок:
Clear-Site-Data: "cache", "cookies", "storage", "executionContexts"
Это эффективная мера по очистке, выполняемая при выходе из системы.
Спецификация Cross-Origin Policies
Spring Security обеспечивает поддержку некоторых важных заголовков спецификации Cross-Origin Policies. Этими заголовками являются:
Заголовок Cross-Origin-Opener-Policy
(COOP) позволяет документу верхнего уровня разорвать связь между своим окном и любыми другими в группе контекста просмотра (например, между всплывающим окном и его открывателем), предотвращая прямой доступ к DOM-модели между ними.
Активация Cross-Origin-Embedder-Policy
(COEP) предотвращает загрузку в документ любых ресурсов из разных источников, которые явным образом не предоставляют документу разрешение на загрузку.
Заголовок Cross-Origin-Resource-Policy
(CORP) позволяет управлять набором источников, которые имеют право добавлять ресурс. Это надежная защита от атак типа Spectre, поскольку она позволяет браузерам блокировать заданный ответ до того, как он попадет в процесс злоумышленника.
Кастомные заголовки
Spring Security содержит механизмы, позволяющие удобно добавлять наиболее распространенные заголовки безопасности в ваше приложение. Однако он также предусматривает перехватчики для добавления кастомных заголовков.
HTTP
Всё взаимодействие по протоколу HTTP, включая статические ресурсы, следует защитить с помощью TLS.
Как фреймворк, Spring Security не обрабатывает HTTP-соединения и поэтому не обеспечивает поддержку HTTPS напрямую. Тем не менее, он предусматривает ряд функций, которые помогают использовать HTTPS.
Переадресация на HTTPS
Если клиент использует HTTP, в конфигурацию Spring Security можно добавить переадресацию на HTTPS как в сервлетном окружении, так и в окружении WebFlux.
Strict Transport Security
Spring Security обеспечивает поддержку механизма Strict Transport Security и активирует его по умолчанию.
Конфигурация прокси-сервера
При использовании прокси-сервера важно убедиться, что приложение было сконфигурировано правильно. Например, многие приложения будут содержать балансировщик нагрузки, который отвечает на запрос example.com/, перенаправляя его на сервер приложений по адресу 192.168.1:8080. Без надлежащей конфигурации сервер приложений не будет знать о существовании балансировщика нагрузки и обработает запрос так, как будто клиент запросил 192.168.1:8080.
Это можно исправить, если использовать RFC 7239, чтобы задать использование балансировщика нагрузки. Чтобы обеспечить совместимость приложения, нужно сконфигурировать сервер приложений таким образом, чтобы он был совместим с заголовками X-Forwarded. Например, Tomcat использует RemoteIpValve, а Jetty – ForwardedRequestCustomizer. Кроме того, пользователи Spring могут использовать ForwardedHeaderFilter.
Пользователи Spring Boot могут использовать свойство server.use-forward-headers
для конфигурирования приложения.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ