Три года назад организацией Mozilla Foundation был разработан новый стандарт политики безопасности, который предотвращает XSS-атаки и другие, связанные с ним виды атак запрещая подгружать и выполнять скрипты с запрещённых ресурсов. Называется он Content Security Policy (CSP), что в переводе означает «Политика безопасности контента».
На момент написания статьи стандарт CSP находится в статусе Candidate Recommendation, что означает возможное принятие этого стандарта в будущем W3C консорциумом. На данный момент все популярные браузеры поддерживают этот стандарт.
Браузер | Версия | Примечания |
---|---|---|
Chrome | 25+ | Полная поддержка |
Firefox | 23+ | |
Opera | 15+ | |
Яндекс.Браузер | ||
Firefox | 4-22 | Поддерживают нестандартный заголовок X-Content-Security-Policy и частично поддерживают стандартный |
IE | 10+ | |
Chrome | 14-24+ | Поддерживают нестандартный заголовок X-Webkit-CSP и частично поддерживают стандартный |
Safari | 5-7 |
Как отсутствие CSP может навредить сайту?
Допустим у вас есть сайт, на котором вы показываете рекламу пользователям и честно зарабатываете деньги. И всё идёт хорошо, пока к вам не начнут ходит пользователи с заражёнными браузерами. Заражённый браузер будет подменять рекламу на вашем сайте на свою и показывать её пользователю. Как следствие — пессимизация со стороны поисковиков и падение дохода. Если же вы введёте политику CSP на своём сайте, то чужая реклама уже не покажется конечному пользователю, потому что сервер с которого реклама будет пытаться загрузиться находится не в белом списке, впрочем обо всё по порядку.
Содержание Content Security Policy
По сути Content Security Policy — это заголовок, который сервер отправляет браузеру. Давайте разберём более детально из чего же он состоит.
Директива | Назначение |
---|---|
default-src | В этой директиве задаются белые списки хостов, которые будут автоматически присвоены не заданным директивам. |
script-srс | Белый список хостов с которых разрешается загрузка javascript |
style-src | Белый список хостов с которых разрешается загрузка css |
object-src | Белый список хостов с которых разрешается загрузка Flash-подобных плагинов |
img-src | Белый список хостов с которых разрешается загрузка картинок |
media-src | Белый список хостов с которых разрешается загрузка аудио и видео |
frame-src | Белый список хостов с которых разрешается загрузка iframe’ов |
font-src | Белый список хостов с которых разрешается загрузка шрифтов |
connect-src | Специальные директивы для XMLHttpRequest, WebSocket и EventSource. Обратите внимание, что для каждой из этих директив задаётся список не урлов, а хостов, с которыми разрешено общаться браузеру. |
report-uri | Url, на который будет отсылаться JSON-отчёт о нарушениях политики. Пример отчёта будет показан ниже в статье. |
Сейчас ещё немного теории, и потом сразу перейдём к практики, потерпите 😉
Ключевое слово | Назначение |
---|---|
‘self’ | Определяет текущий хост. |
‘none’ | Запрещает всё. «You shall not pass!» 🙂 |
‘unsafe-inline’ | Используется только в директивах script-src и style-src . Разрешает выполнять inline-скрипты на странице. Не рекомендую использвать это ключевое слово, т.к. это развязывает руки злоумышленнику и даёт право исполнять любые инлайновые скрипты на странице. Простыми словами, это дыра в безопасности. |
‘unsafe-eval’ | Используется только в script-src и разрешает кодогенерацию, например: eval, new Function, setTimeout(‘var foo = «bar» ‘, 7) |
Устанавливаем Content Security Policy на сайт
Как я уже писал выше, CSP — это обычный http заголовок, который можно наблюдать в консоли Google Chrome, наряду с остальными заголовками:
Чтобы лучше понять как работает Content Security Policy, давайте немного поэкспериментируем. Создайте файл index.php и напишите в него следующий код:
<?php $csp = "Content-Security-Policy-Report-Only: " . "default-src 'self'; " . "report-uri http://localhost/csp/collector.php"; header($csp); ?> <!DOCTYPE html> <html lang="ru"> <head> <meta charset="UTF-8"> <title>CSP test</title> </head> <body> <?php foreach (headers_list() as $header) { echo $header . '<br>'; } ?> <script> console.log('Инлайн скрипт работает!'); </script> <img src="https://zabolotskikh.com/wp-content/themes/fresh/img/logo.gif" alt="Логотип"/> </body> </html>
Обратите внимание, что в http заголовке я указал Content-Security-Policy-Report-Only он аналогичен Content-Security-Policy, с той лишь разницей, что не блокирует ресурсы, а только оповещает о нарушении. Крайне полезная штука при тестировании системы перед внедрением!
Давайте разберёмся, что же мы понаписали. Первым делом мы указали в http заголовке директиву default-src 'self'
, что означает что подгружать ресурсы можно только со своего хоста. Любые инлайн скрипты и css запрещены. Ок, идём дальше и видим:
<script> console.log('Инлайн скрипт работает!'); </script> <img src="https://zabolotskikh.com/wp-content/themes/fresh/img/logo.gif" alt="Логотип"/>
Т.е. попробуем выполнить инлайн скрипт и загрузить картинку со стороннего хоста. И посмотрим как отреагирует наш бравый защитник:
CSP отреагировал адекватно. Т.е. подгрузил картинку и выполнил инлайновый javascript, но при этом сказал нам в консоли «ата-та!», а именно: сообщил о том, что произошло два нарушения.
Теперь давайте изменим заголовок с Content-Security-Policy-Report-Only на Content-Security-Policy и посмотрим что будет:
Пендальф CSP никого не пустил.
Инлайн скрипт не был выполнен, а картинка не загрузилась. Круто, правда?
Теперь можете поэкспериментировать самостоятельно. Вам пригодятся две таблички выше в статье, в которых мы рассмотрели директивы и ключевые слова для указания хостов. Попробуйте заменить 'self'
на https://zabolotskikh.com/
и посмотрите что произойдет — картинка сможет загрузиться, так как её сервер был указан в белом списке.
Хочу обратить ваше внимание, что хост желательно указывать с протоколом, так как в противном случае протокол будет взят из текущего хоста. Например, если вы укажите хост как zabolotskikh.com
, а ваш сервер работает по протоколу https, то в белом списке окажется https://zabolotskikh.com/
.
Обработка отчётов
Вся прелесть этой политики в том, что помимо блокирования, мы также можем собирать отчёты о нарушениях! Помните в примере в http заголовке мы указали url report-uri http://localhost/csp/collector.php
для сбрасывания отчётов? Как не сложно догадаться на этот url будут отправляться все отчёты о нарушениях.
Вот так выглядит отчёт о нарушении (в формате JSON):
{ "csp-report": { "document-uri": "http://localhost/csp/", "referrer": "", "violated-directive": "default-src 'self'", "original-policy": "default-src 'self'; report-uri http://localhost/csp/collector.php", "blocked-uri": "https://zabolotskikh.com" } }
С этим отчётом вы можете делать всё что угодно, например сохранять в базу, отправлять на почту. Я предлагаю записывать все нарушения в csv файл. Давайте сделаем это!
Создайте файл collector.php и напишите в него следующие строки:
<?php http_response_code(204); $report = file_get_contents('php://input'); $report = json_decode($report, true); if (empty($report)) { exit; } $report = $report['csp-report']; $delimiter = '|'; $csvLine = ''; $csvLine .= !empty($report['document-uri']) ? $report['document-uri'] : $delimiter; $csvLine .= !empty($report['referrer']) ? $delimiter . $report['referrer'] : $delimiter; $csvLine .= !empty($report['violated-directive']) ? $delimiter . $report['violated-directive'] : $delimiter; $csvLine .= !empty($report['original-policy']) ? $delimiter . $report['original-policy'] : $delimiter; $csvLine .= !empty($report['blocked-uri']) ? $delimiter . $report['blocked-uri'] : $delimiter; $csvLine .= !empty($report['status-code']) ? $delimiter . $report['status-code'] : $delimiter; $csvLine .= "\r\n"; file_put_contents('report.csv', $csvLine, FILE_APPEND);
Теперь ещё раз обновите страницу и посмотрите в директорию http://localhost/csp/. У вас должен появиться файл report.csv с двумя строчками кода:
Ура! Мы поймали отчёт о нарушениях и записали его в файл. Можете показать этот файл друзьям 😉 А лучше всего начните внедрять CSP на свой сайт, сначала в режиме тестирования, а потом в «боевом» виде. На этапе тестирования отчёт поможет вам анализировать какие директивы реагируют на нарушения и соответствующим образом настраивать их.
Скачать файлы с примерами из статьи
Полезные материалы по Content Security Policy
- http://w3c.github.io/webappsec-csp/ — спецификация стандарта.
- https://mathiasbynens.be/notes/csp-reports — интересная статья на английском про CSP.
- https://github.com/immrr/csp-report — скрипт для обработки отчётов о нарушениях и записи их в базу.
- http://www.cspplayground.com/csp_validator — валидатор CSP http заголовка! Очень полезная штуковина, вы можете проверить свой заголовок на корректность, согласно спецификациям стандарта.
А можно подробней, что куда писать в wordpress?
Для WP есть специальный плагин: http://people.mozilla.org/~bsterne/content-security-policy/wordpress.html
Но он не обновлялся довольно долго, попробуйте в официальном репозитории ещё поискать.
А если не использовать плагин для WordPress, а установить ваш вариант защиты, он будет так же работать? Или обязательно плагин ставить?
а что за прикол такой в логах бывает ………./collector.php|data|200
что бы это могло значить?
Не знаю, может данные не поступили.
Подскажите, а есть разница какой doctype?
Не могу понять почему у меня на одном сайте обрезается политика CSP.
Мне кажется разницы нет.
Борис помоги пожалуйста составить Content Security Policy для моего сайта http://www.cherneenet.ru
Сергей, благодарю за обращение, но у меня на данный момент нет на это времени.
А может подскажешь кого-нибудь, я уже весь инет перерыл, толку ноль. Может какие-нибудь сервисы есть?
У тебя сайт на WP, для него же специальный плагин есть: http://people.mozilla.org/~bsterne/content-security-policy/wordpress.html
Я поспрашиваю у друзей, может кто сможет помочь, но это не бесплатно будет.
Пробовал плагин, не работает, он уже 5 лет не обновлялся. Спроси у друзей, потом напишешь мне. Спасибо.
ВСе сдела по инструкции, Report не работате.!
Привет! А не подскажешь такой момент.
Благополучно блокировал яндекс советник через CSP до недавнего времени(( Конкретно в google chrome перестало блокировать… похоже обновили расширение и теперь подгружают через него или еще как.. Вобщем долбанный советник нашел лазейку в Хроме(( Есть какие то варианты блочить расширения хрома.. или типа того?
Оценка статьи — 4 балла.
Не хватает ссылки на спецификацию: http://w3c.github.io/webappsec-csp/
Не сказано, что может использоваться для указания источника, помимо ключевых слов и URL (см. спецификацию, раздел 2.2.1. Source Lists)
Здравствуйте.
А куда вставлять X-WebKit-CSP и X-Content-Security-Policy в примере:
$csp = «Content-Security-Policy-Report-Only: »
. «default-src ‘self’; »
. «report-uri http://localhost/csp/collector.php«;
header($csp);
Здравствуйте! В код сайта на страницу, где предполагается использование.
Здравствуйте! А вы можете помочь с внедрением этой технологии на сайт на платной основе?
Существует ли CSP, который полностью совместим с Гугл Адсенс? Он же подгружает множество других хостов….
Рекомендую вам рассмотреть переход на https, если есть https, то CSP по сути не нужен.
Пробую дать доступ на своем сайте для выгрузки, и не пашит Сайт