Content Security Policy (CSP)
=============================

**Content Security Policy** (CSP) - это дополнительный уровень безопасности, позволяющий распознавать и устранять определённые типы атак, таких как Cross Site Scripting (XSS (en-US)) и атаки внедрения данных. Спектр применения этих атак включает, но не ограничивается кражей данных, подменой страниц и распространением зловредного ПО.

CSP разрабатывался с возможностью полной обратной совместимости (за исключением CSP version 2, в которой были намеренно определены некоторые противоречия блокирующие обратную совместимость; с деталями можно ознакомиться здесь, в пункте 1.1). Браузеры, которые не поддерживают CSP, все ещё могут работать с серверами, которые поддерживают CSP, и наоборот: браузеры, в которых поддержка CSP отсутствует, будут её игнорировать, продолжая работу в соответствии со стандартными правилами ограничения домена для загрузки контента. В случае, если сайт не предоставляет CSP-заголовки, браузеры, в свою очередь, будут использовать стандартные правила ограничения домена.

Для того чтобы включить CSP, необходимо настроить сервер так, чтобы в ответах он использовал HTTP-заголовок `Content-Security-Policy` (en-US) (в различных примерах и документации можно встретить вариант заголовка `X-Content-Security-Policy`. Он является устаревшим и определять его не нужно).

В качестве альтернативы настройке сервера, вы можете сконфигурировать CSP с помощью элемента `<meta>`. Например, так: `<meta http-equiv="Content-Security-Policy" content="default-src 'self'; img-src https://*; child-src 'none';">`

Угрозы
------

### Межсайтовый скриптинг

Основная цель создания CSP заключается в устранении XSS-атак и сборе данных об их попытках. XSS-атаки используют доверие браузера к контенту, полученному с сервера. Зловредные скрипты исполняются в браузере жертвы, поскольку браузер доверяет источнику, даже когда скрипт поставляется не оттуда, откуда кажется.

CSP даёт возможность администраторам серверов снизить или полностью устранить вектора, по которым злоумышленники могут провести XSS, с помощью определения доменов, которые браузер клиента должен считать доверенными источниками исполняемых скриптов. В таком случае, браузер, совместимый с CSP, будет исполнять только те скрипты, которые были получены из списка разрешённых источников, и игнорировать прочие (в т.ч. встраиваемые скрипты и обработчики событий, указанные непосредственно в HTML-атрибутах).

В качестве крайней меры защиты, сайты, которые хотят запретить исполнение скриптов, могут настроить это поведение глобально, с помощью соответствующей опции.

### Пакетный сниффинг

В дополнение к ограничению количества доверенных доменов, с которых разрешается получать контент, можно также ограничить список используемых протоколов; например (в идеале и это крайне желательно с точки зрения обеспечения безопасности), сервер может поставить ограничение на получение контента только по HTTPS. Завершённая стратегия защиты передачи данных должна включать в себя не только принуждение к использованию HTTPS, но также и пометку всех кук с помощью специального флага, а также перенаправление запросов с HTTP на HTTPS. Сайты также могут использовать `Strict-Transport-Security` HTTP-заголовок, чтобы обеспечить подключение к ним браузеров только по защищённому каналу\*\*.\*\*

Использование CSP
-----------------

Настройка CSP включает в себя добавление на страницу HTTP-заголовка `Content-Security-Policy` (en-US) и его настройку в соответствии со списком доверенных источников, из которых пользователь может получать контент. Например, страница, на которой происходит загрузка и отображение изображений может разрешать их получение из любых источников, но ограничить отправку данных формы конкретным адресом. При правильной настройке, Content Security Policy поможет защитить страницу от атак межсайтового скриптинга. Данная статья описывает как правильно настроить необходимые заголовки и примеры, как это сделать.

### Определение политики

Вы можете начать настройку `Content-Security-Policy` (en-US) с определения HTTP-заголовка и указания какую политику использовать:
```

Content-Security-Policy: policy
```


Где policy - это строка, содержащая директивы, описывающие вашу Content Security Policy.

### Создание политики

Политика описывается с помощью специальных директив, каждая из которых отвечает за отдельный вид ресурсов или policy area. Политика обязательно должна содержать директиву `default-src` (en-US), которая будет использоваться для тех ресурсов, для которых не будет описано отдельных правил (полный список вы можете найти в описании директивы `default-src` (en-US)). Для того чтобы предотвратить исполнение встраиваемых скриптов и заблокировать использование `eval()`, необходимо определить директиву `default-src` (en-US) или `script-src` (en-US). Также использование директивы `default-src` (en-US) или `style-src` (en-US) позволит ограничить использование встраиваемых стилей как в `style`-атрибутах, так и в тэгах `<style>`.

Примеры: Распространённые случаи применения
-------------------------------------------

В данном разделе приводятся наиболее распространённые сценарии использования CSP.

### Пример 1

Вы хотите ограничить источники контента только исходным сервером (исключая поддомены)
```

Content-Security-Policy: default-src 'self'
```

### Пример 2

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

Content-Security-Policy: default-src 'self' *.trusted.com
```

### Пример 3

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

Content-Security-Policy: default-src 'self'; img-src *; media-src media1.com media2.com; script-src userscripts.example.com
```


При такой настройке, весь контент доступен для получения только с исходного домена, со следующими исключениями:

* Изображения могут быть получены из любого источника (источник - "\*").
* Другие медиа-файлы доступны только с media1.com и media2.com (но не с их поддоменов).
* Исполняемый код доступен только с userscripts.example.com.
### Пример 4

Вы хотите удостовериться, что весь получаемый контент для онлайн-банкинга идёт по SSL и атакующий не сможет обрабатывать запросы:
```

Content-Security-Policy: default-src https://onlinebanking.jumbobank.com
```


При данной настройке сервер будет позволять загрузку страниц только по HTTPS и только из одного источника - onlinebanking.jumbobank.com.

### Пример 5

Для просмотра писем в почтовом клиенте вы хотите разрешить использование HTML внутри письма, а также позволить загрузку изображений из любых источников, но запретить использование любого JavaScript-кода и прочий потенциально опасный контент.
```

Content-Security-Policy: default-src 'self' *.mailsite.com; img-src *
```


Заметьте, что в настройке политики отсутствует директива `script-src` (en-US); при такой настройке CSP при загрузке скриптов будут использоваться настройки, определяемые директивой `default-src` (en-US), следовательно все скрипты могут быть загружены только с исходного домена.

Тестирование настройки политики
-------------------------------

Для облегчения развёртывания можно настроить развёртывание CSP в режиме report-only. Таким образом, политика не будет ограничивать загрузку, но будет сообщать обо всех нарушениях на указанный в заголовке URI. Кроме того, заголовок report-only может использоваться для тестирования новой политики без полноценного развёртывания.

Для определения вашей политики вы можете использовать заголовок `Content-Security-Policy-Report-Only` (en-US) следующим образом:
```

Content-Security-Policy-Report-Only: policy
```


В случае, если оба заголовка (`Content-Security-Policy-Report-Only` (en-US) и `Content-Security-Policy` (en-US)) были определены одновременно в одном ответе сервера, обе политики будут обработаны. Политики, описанные в заголовке `Content-Security-Policy` будут применены, в то время как политики, описанные в заголовке `Content-Security-Policy-Report-Only`, создадут отчёты, но применены не будут.

Настройка отправки отчётов
--------------------------

По умолчанию, отправка отчётов не производится. Для того чтобы включить отправку отчётов, необходимо в вашей политике определить директиву `report-uri` (en-US) и указать как минимум один URI, куда будут направляться отчёты:
```

Content-Security-Policy: default-src 'self'; report-uri http://reportcollector.example.com/collector.cgi
```


Кроме того, необходимо настроить свой сервер на получение этих отчётов; вы можете хранить и обрабатывать эти отчёты как считаете нужным.

Синтаксис отчёта о происшествиях
--------------------------------

Объект отчёта в формате JSON содержит следующие поля:

`blocked-uri`

URI ресурса, заблокированного в соответствии с настройками политики. Если заблокированный адрес отличается от адреса страницы, то он будет сокращён до схемы, хоста и порта.


`disposition`

Принимает значения `"enforce"` или `"reporting"` в зависимости от того, какой заголовок используется `Content-Security-Policy-Report-Only` (en-US) или `Content-Security-Policy`.

`document-uri`

URI страницы, на которой произошло нарушение.

`effective-directive`

Директива, исполнение которой привело к нарушению.

`original-policy`

Исходная политика, описываемая в заголовке `Content-Security-Policy`.

`referrer`

Реферер, который привёл к нарушению.

`script-sample`

Первые 40 символов встроенного скрипта или стиля, спровоцировавшего нарушение.

`status-code`

The HTTP status code of the resource on which the global object was instantiated.

`violated-directive`

Директива, которая была нарушена.

Пример отчёта о происшествии
----------------------------

Возьмём страницу, расположенную по адресу `http://example.com/signup.html`. Для неё используется следующая политика, запрещающая загрузку всего кроме CSS-файлов с `cdn.example.com`.
```

Content-Security-Policy: default-src 'none'; style-src cdn.example.com; report-uri /_/csp-reports
```


HTML-код страницы `signup.html` выглядит следующим образом:


```html
<!doctype html>
<html>
  <head>
    <title>Sign Up</title>
    <link rel="stylesheet" href="css/style.css" />
  </head>
  <body>
    ... Content ...
  </body>
</html>
```


Можете заметить ошибку? CSS разрешено загружать только с `cdn.example.com`, в то время как веб-сайт пытается загрузить его используя основной домен (`http://example.com`). Браузер поддерживающий CSP отправит отчёт о нарушении политики в POST-запросе к `http://example.com/_/csp-reports` в момент обращения к странице (`signup.html`):
```

{
  "csp-report": {
    "document-uri": "http://example.com/signup.html",
    "referrer": "",
    "blocked-uri": "http://example.com/css/style.css",
    "violated-directive": "style-src cdn.example.com",
    "original-policy": "default-src 'none'; style-src cdn.example.com; report-uri /_/csp-reports"
  }
}
```


Как видите, отчёт включает полный путь к ресурсу нарушающему политику в `blocked-uri`. Правда, это не всегда так. К примеру, когда `signup.html` попытается загрузить CSS с `http://anothercdn.example.com/stylesheet.css`, браузер *не* будет включать полный путь, а ограничится лишь доменом (`http://anothercdn.example.com`). Спецификация CSP поясняет это странное поведение. В целом, это делается для предотвращения утечек чувствительной информации о перекрёстных ресурсах

Совместимость с браузерами
--------------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

Для некоторых версий Safari существует специфическая несовместимость реализации CSP. Если установить заголовок Content Security Policy без заголовка Same Origin, то браузер начнёт блокировать и создавать ложно-положительные отчёты о нарушении политики для всего контента, как с запрашиваемого источника, так и из внешних источников.

Смотрите также:

* `Content-Security-Policy` (en-US)
* `Content-Security-Policy-Report-Only` (en-US)
* Content Security in WebExtensions
* Display security and privacy policies In Firefox Developer Tools