Content security policy header

Три года назад организацией Mozilla Foundation был разработан новый стандарт политики безопасности, который предотвращает XSS-атаки и другие, связанные с ним виды атак запрещая подгружать и выполнять скрипты с запрещённых ресурсов. Называется он Content Security Policy (CSP), что в переводе означает «Политика безопасности контента».

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

Поддержка Content Security Policy в различных браузерах

Браузер Версия Примечания
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 — это заголовок, который сервер отправляет браузеру. Давайте разберём более детально из чего же он состоит.

Директивы заголовка CSP

Директива Назначение
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 и напишите в него следующий код:

Обратите внимание, что в http заголовке я указал Content-Security-Policy-Report-Only он аналогичен Content-Security-Policy, с той лишь разницей, что не блокирует ресурсы, а только оповещает о нарушении. Крайне полезная штука при тестировании системы перед внедрением!

Давайте разберёмся, что же мы понаписали. Первым делом мы указали в http заголовке директиву default-src ‘self’ , что означает что подгружать ресурсы можно только со своего хоста. Любые инлайн скрипты и css запрещены. Ок, идём дальше и видим:

Т.е. попробуем выполнить инлайн скрипт и загрузить картинку со стороннего хоста. И посмотрим как отреагирует наш бравый защитник:

CSP отреагировал адекватно. Т.е. подгрузил картинку и выполнил инлайновый javascript, но при этом сказал нам в консоли «ата-та!», а именно: сообщил о том, что произошло два нарушения.

Читайте также:  Полис емиас запись к врачу

Теперь давайте изменим заголовок с Content-Security-Policy-Report-Only на Content-Security-Policy и посмотрим что будет:

Пендальф CSP никого не пустил.

Инлайн скрипт не был выполнен, а картинка не загрузилась. Круто, правда?

Теперь можете поэкспериментировать самостоятельно. Вам пригодятся две таблички выше в статье, в которых мы рассмотрели директивы и ключевые слова для указания хостов. Попробуйте заменить ‘self’ на http://zabolotskikh.com/ и посмотрите что произойдет — картинка сможет загрузиться, так как её сервер был указан в белом списке.

Хочу обратить ваше внимание, что хост желательно указывать с протоколом, так как в противном случае протокол будет взят из текущего хоста. Например, если вы укажите хост как zabolotskikh.com , а ваш сервер работает по протоколу https, то в белом списке окажется https://zabolotskikh.com/ .

Обработка отчётов

Вся прелесть этой политики в том, что помимо блокирования, мы также можем собирать отчёты о нарушениях! Помните в примере в http заголовке мы указали url report-uri http://localhost/csp/collector.php для сбрасывания отчётов? Как не сложно догадаться на этот url будут отправляться все отчёты о нарушениях.
Вот так выглядит отчёт о нарушении (в формате JSON):

С этим отчётом вы можете делать всё что угодно, например сохранять в базу, отправлять на почту. Я предлагаю записывать все нарушения в csv файл. Давайте сделаем это!

Создайте файл collector.php и напишите в него следующие строки:

Теперь ещё раз обновите страницу и посмотрите в директорию 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?

Что такое Content Security Policy

С год назад в рунете начала бурно цвести такая схема серого заработка как плагины к браузерам. Юзер ставит плагин для скачки скажем музыки из ВК, или для поиска скидок в магазинах или ещё какие плагины. Плагин работает, свои функции выполняет и бесплатен. А потом юзеры начинают замечать ( или не начинают ), что любимые сайты как-то резко изменились, начали вешать больше рекламы, да ещё порой не очень приятной ( порно, бады и прочее ).

Иногда такой гадости не происходит, а плагин просто подменяет своим кодом рекламу на сайте. Банально вырезает ваш Adsense и ставит свой. Такого юзер вообще не замечает, владелец сайта может почувствовать некоторое падение дохода.

Хуже всего ситуация когда ваши посетители активно используют такие плагины, которые заменяют вашу белую рекламу рекламой чего-то не приличного. Технически это может выглядеть так что пользователь кликая по такой рекламе переходит на неё именно с вашего сайта. Мало того что вы теряете доход, теряете в иммидже ( ваш посетитель ведь не понимает что вы не виноваты, думает что именно владелец сайта завесил весь сайт порно ), но иногда поисковые системы могут понизить вас выдаче за такие переходы с вашего сайта. Поищите такие истории на серче. И, хотя Я уже объявил, что за такие переходы пессимизировать не будет, но вы же понимаете – лучше обезопасить себя. Сделать это возможно как раз с помощью Content Security Policy

Также подмена контента на странице может осуществляется из-за вирусов, троянов, стороннего программного обеспечения, виджетов на сайте и т.д.

Рекомендую почитать ветку на серче , там масса ценной информации, не пожалейте времени прочтите её всю. И пользуясь случаем спасибо все её активным участникам. Особенно Ladycharm ( вообще на посты этого человека на серче стоит обращать внимание, часто очень ценные вещи пишет ), ctit, samimages ( за код для репортов ).

Ещё полезная ссылка на статью 2013 года в блоге Яндекса на Хабре. Там есть упоминания про утилиты для тестирования политик CSP, я их не пробовал, но возможно они вам пригодятся.

Читайте также:  Активация пин кода стим

Как определить что вам нужно включить Content Security Policy

Проверьте в любой установленной у вас метрике наличие переходов с вашего сайта на сайты на которые переходов быть по определению не должно. Очень хорошо необходимость настройки Content Security Policy видно в метрике Live Internet. В Яндекс Метрике это не так очевидно ( что странно ).

Открываете статистику LI. Пункт переходы на сайты. Если вы видите здесь значительное количество переходов на совершенно левые сайты, то вам стоит задуматься о настройке CSP

Какие риски при неправильной настройке CSP

CSP запрещает сторонним скриптам менять содержимое страницы. Буквально вставлять код, картинки и прочее. Большинство современных сайтов используют у себя на сайте контекстную рекламу, счетчики, виджеты социальных кнопок, виджеты соцсетей, кнопки метрик, сторонние системы комментирования и многое другое. Если вы не правильно настроите Content Security Policy что-то из этого может перестать работать совсем или станет работать не так как ожидалось. Отловить некоторые баги порой очень сложно и не очевидно.

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

В итоге если вы не уверены, что делаете, если левого трафика не много, возможно вообще не стоит всем этим заниматься.

Обратите внимание, то что делал я – хорошо работает в моем случае, как будет работать у вас я не знаю. Тут часто многое индивидуально. Я гарантий никаких не даю и ничего не обещаю. Вы всё делаете на свой страх и риск, ко мне без претензий.

Итак как настроить Content Security Policy

Суть настройки Content Security Policy это отправка браузеру посетителя необходимых http заголовков. Если браузер поддерживает эти заголовки, то он будет действовать в соответствии с политиками которые вы пропишите в этом заголовке. Сделать это можно различными способами.

В принципе CSP можно реализовать в виде плагина для WordPress ( более того какие то плагины уже опубликованы в репозитории ). Или просто в functions.php темы отдавать нужные заголовки на экшен send_headers . В некоторых случаях вариант через php единственно возможный ( если нет mod_headers например, или сервер живет под Nginx, к настройкам которого вас не подпустят ). В этой статье про способ на php речи не идет. Если кому-то будет нужно допишу.

Можно вообще описать заголовок Content-Security-Policy в meta вашей темы, но у этого способа есть серьезные ограничения. Этот способ настройки CSP я бы очень не рекомендовал.

Мой случай это WordPress под апачем. Nginx есть, но настроен только для отдачи статики, поэтому все манипуляции делаю в .htaccess в корне сайта. Итак у нас есть апач и доступ к файлу .htaccess в корне вашего сайта. Чтобы отправить заголовки кодом в .htaccess вам нужен модуль апача mod_headers. Проверить его наличие легко, пишем такой код в самое начало .htaccess.

Content Security Policy (CSP, политика защиты контента) — это механизм обеспечения безопасности, с помощью которого можно защищаться от атак с внедрением контента, например, межсайтового скриптинга (XSS, cross site scripting). CSP описывает безопасные источники загрузки ресурсов, устанавливает правила использования встроенных стилей, скриптов, а также динамической оценки JavaScript — например, с помощью eval. Загрузка с ресурсов, не входящих в «белый список», блокируется.

Принцип действия

CSP сейчас является кандидатом в рекомендации консорциума W3C. Для использования политики страница должна содержать HTTP-заголовок Content-Security-Policy с одной и более директивами, которые представляют собой «белые списки». В версии 1.0 поддерживаются следующие директивы:

  • default-src
  • script-src
  • object-src
  • style-src
  • img-src
  • media-src
  • frame-src
  • font-src
  • connect-src

В default-src перечисляются разрешённые источники по умолчанию для остальных директив. Если какая-то директива не указана в заголовке, то политика применяется согласно списку default-src .

Для всех директив действуют следующие правила:

  • Для ссылки на текущий домен используется self .
  • В перечне URL адреса разделяются пробелами.
  • Если в рамках данной директивы ничего не должно загружаться, то применяется none . Например, object-src ‘none’ запрещает загрузку любых плагинов, включая Java и Flash.

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

Content-Security-Policy: default-src ‘self’;

Попытка загрузки ресурсов из иных доменов будут пресекаться браузером с выдачей уведомления в консоли:

По умолчанию CSP ограничивает исполнение JavaScript путём запрета встроенных скриптов и динамической оценки кода. В комбинации с «белыми списками» это позволяет предотвращать атаки с внедрением контента. Например, XSS-атаку с внедрением тэга инлайн-скрипта:

Читайте также:  Telegram как создать канал

Загрузка внешних скриптов, которые не включены в CSP, также будет пресечена:

На данный момент в перечне URL нельзя прописывать пути ( http://cdn.example.com/path ), можно лишь перечислять сами домены ( http://cdn.example.com ). Зато поддерживаются символы подстановки, так что вы можете описать сразу все поддомены ( http://*.example.com ).

Директивы не наследуют права от предыдущих директив. Каждая директива, включённая в заголовок CSP, должна содержать перечень разрешённых доменов/поддоменов. В следующем примере default-src и style-src содержат ключевое слово self , а script-src и style-src содержат домен http://cdn.example.com :

Если вам нужно указать хосты для загрузки данных, то нужно указать ключевое слово data: img-src ‘data’; .

Помимо списков доменов, директивы script-src и style-src поддерживают ключевые слова unsafe-inline и unsafe-eval .

  • unsafe-inline используется для разрешения инлайн-стилей и скриптов style и script . Также это ключевое слово разрешает инлайн-атрибуты CSS style , инлайн-обработчики событий (onclick, onmouseover и т.д.) и javascript-ссылки наподобие a href="javascript:foobar()" . CSP работает по принципу «если что-то не упомянуто, значит запрещено». То есть при отсутствии ключевого слова unsafe-inline все инлайн-тэги style и script будут блокироваться.
  • unsafe-eval используется только в директиве script-src . Если это ключевое слово не указано, то блокируется любая динамическая оценка кода, включая использование eval , конструктор функций и передачу строковых в setTimeout и setInterval .

Поддержка браузерами

На текущий момент большинство браузеров и их версий уже поддерживают CSP 1.0. IE снова отличился: в 10 и 11 версиях обеспечена лишь частичная поддержка с помощью заголовка X-Content-Security-Policy . Судя по всему, поддерживается только опциональная директива sandbox.

Получение отчётов о нарушениях CSP

Как уже упоминалось, сообщения обо всех нарушениях политики безопасности логгируются в консоли браузера. Это удобно, пока вы только разрабатываете сайт, но после развёртывания нужен более практичный способ получения отчётов о нарушениях. Для этого можно использовать директиву report-uri . Каждый раз, когда регистрируется нарушение CSP, директива отправляет на указанный адрес запрос HTTP POST. В теле запроса содержится JSON-объект, в котором указаны все необходимые подробности.

Допустим, у нас есть такая CSP:

Это означает, что браузер может загружать ресурсы только с нашего собственного домена. Но нам нужно использовать сервис Google Analytics, который будет пытаться скачивать JavaScript с www.google-analytics.com. А это уже нарушение нашей CSP. В этом случае report-uri отправит запрос со следующим JSON:

Content-Security-Policy-Report-Only

Если вы пока не уверены, стоит ли внедрять у себя CSP, то можно попробовать вместо заголовка Content-Security-Policy использовать Content-Security-Policy-Report-Only . В этом случае CSP будет регистрировать нарушения без какого-либо блокирования ресурсов. Можно даже использовать одновременно Content-Security-Policy и Content-Security-Policy-Report-Only , обкатывая на второй те или иные конфигурации.

Прописывание заголовка

HTTP-заголовок можно прописать прямо в конфигурационных файлах на сервере:

Также многие языки программирования и фреймворки позволяют добавлять заголовки программно (например, PHP, Node.js):

CSP в дикой природе

Давайте посмотрим, как CSP внедрён в Facebook:

Обратите внимание на использование символов подстановки для описания поддоменов, а также номеров портов в connect-src .

А теперь вариант Twitter:

Здесь везде прописаны https: , то есть принудительно используется SSL.

CSP Level 2

Также является кандидатом в рекомендации. В CSP Level 2 сделаны следующий нововведения:

  • base-uri : позволяет документу манипулировать базовым URI страницы.
  • Вместо frame-src теперь применяется child-src .
  • form-action : позволяет документу размещать HTML-формы.
  • frame-ancestors : регламентирует способ встраивания данного документа в другие документы. Работает как заголовок X-Frame-Options, для замены которого, вероятно, и предназначен.
  • plugin-types : разрешает загрузку конкретных плагинов — Flash, Java, Silverlight и т.д.

В JSON, содержащихся в отчётах о нарушениях, появились два новых поля:

  • effective-directive : здесь указано название директивы, которая была нарушена.
  • status-code : HTTP-код состояния запрошенного ресурса. Если нарушающий запрос делался не через HTTP, то ставится 0.

Также в CSP Level 2 появилась возможность разрешать инлайн-скрипты и стили с помощью nonce-значений и хэшей.

Nonce — это генерируемая случайным образом на сервере строковая переменная. Она добавляется в CSP-заголовок:

и в тэг инлайн-скрипта:

Если вы захотите использовать хэши, то сначала их нужно сгенерировать на сервере и включить в заголовок CSP, соответственно в директивы style-src или script-src . Перед рендерингом страницы браузер вычисляет хэш скрипта/стиля, и если он совпадает с указанным, то выполнение разрешается.

Пример хэша, сгенерированного из строковой console.log(‘Hello, SitePoint’); с помощью алгоритма Sha256 (base64).

Во время рендеринга страницы браузер для каждого инлайн-скрипта вычисляет хэши и сравнивает с перечисленными в CSP. Приведённый выше хэш позволяет выполнить скрипт: