Script nonce что это
Использование политики безопасности контента (CSP) для защиты веб-приложений
Политика безопасности контента (Content Security Policy — CSP) — это стандарт компьютерной безопасности, обеспечивающий дополнительный уровень защиты от межсайтовых сценариев (XSS), clickjacking (перехвата кликов) и других атак с использованием кода, основанных на выполнении вредоносного контента в контексте доверенной веб-страницы. Используя подходящие директивы CSP в заголовках ответа HTTP, вы можете выборочно указать, какие источники данных должны быть разрешены в вашем веб-приложении. В этой статье описано, как использовать заголовки CSP для защиты сайтов от атак XSS и других попыток обойти политику CSP.
Зачем нам нужен CSP?
В то же время злоумышленники используют атаки с использованием cross-site scripting (XSS), чтобы обманным путем заставить веб-сайты, которым доверяет пользователь, распространять вредоносный код. Без дополнительных мер безопасности браузер выполнит весь код из доверенного источника и так как он не может определить, какой код является допустимым, то любой внедренный вредоносный код также выполнится.
Content Security Policy (CSP) — стандартизированный набор директив, которые сообщают браузеру, каким источникам контента можно доверять, а какие следует блокировать. Используя тщательно определенные политики, вы можете ограничить содержимое браузера, чтобы устранить многие распространенные векторы атак и значительно снизить риск атаки XSS. По умолчанию CSP также применяет современные стили кодирования сценариев для дополнительной безопасности.
Истории и поддержка браузеров
Content Security Policy — это рекомендация рабочей группы W3C по безопасности веб-приложений. Версия 1 (или уровень 1) была предложена в 2012 году, Level 2 — в 2014 году, а Level 3 разрабатывается с 2015 года в качестве проекта. Хотя это всего лишь рекомендации, создатели браузеров быстро внедрили CSP, начиная с Firefox 4. Подавляющее большинство современных браузеров поддерживают все или почти все директивы уровня 2, и в этой статье описывается уровень 2 CSP как фактический текущий стандарт.
Реализации CSP использовали 3 разных имени заголовка политики безопасности контента, в зависимости от браузера и времени принятия:
Использование директив CSP
CSP позволяет определять различные ограничения содержимого с помощью директив, обычно указанных в заголовках ответа HTTP. Вот пример добавления заголовков CSP на веб-сервер Apache:
При необходимости вы также можете указать желаемые директивы на уровне страницы, используя метатеги HTML. Вот пример, который устанавливает ту же политику, что и выше:
Каждая директива состоит из имени, за которым следует одно или несколько значений, и заканчивается точкой с запятой. Вы можете использовать подстановочный знак * для обобщения целых значений, поддоменов, схем и портов:
Этот заголовок позволяет использовать источники из любого субдомена example.com (но не самого example.com) по любой схеме (http, https и т.д.).
Официальная рекомендация W3C содержит полный список директив с более формальными определениями, но следующий обзор должен дать вам хорошее представление о наиболее часто используемых.
Директивы белого списка источников
Основной целью CSP является ограничение источников веб-контента, поэтому существует множество директив для указания разрешенных источников для различных типов ресурсов. Как только заголовок Content-Security-Policy указан, браузер будет отклонять любой контент из источников, которые явно не занесены в белый список, с использованием любой из приведенных ниже директив. Исходные значения разделены пробелами и могут включать как URL-адреса, так и специальные ключевые слова ‘none’, ‘self’, ‘unsafe-inline’ и ‘unsafe-eval’ (подробно обсуждается ниже). Обратите внимание, что каждая директива может быть указана только один раз в том же заголовке, а ключевые слова должны быть введены в одинарные кавычки.
Написание JavaScript и CSS с CSP
Встроенный код является основным вектором нападения, потому что он всегда выполняется в текущем контексте, поэтому его нельзя ограничивать. Когда CSP включен, он блокирует весь встроенный код по умолчанию. Это означает, что никаких встроенных стилей или встроенных сценариев не должно существовать, включая встроенные обработчики событий или javascript: URL поэтому любой новый код должен следовать передовым методам использования исключительно внешних файлов сценариев и стилей. Ключевое слово unsafe-inline разрешает встроенный код для всех или некоторых источников скриптов, но W3C рекомендует избегать его, где это возможно.
Например, страница HTML и JavaScript старого стиля может содержать код сценария как в тегах Want to click the button?
Чтобы преобразовать это в современный и совместимый с CSP стиль, поместите сценарий в отдельный файл и используйте HTML чисто декларативно, что-то вроде:
Даже после того, как типичные векторы атак были заблокированы, злоумышленники все равно могут выполнить сценарий, если используется динамически запускаемый (evaluated) код. Вот почему CSP также блокирует все функции запуска строк по умолчанию, включая eval (), new Function (), setTimeout ([string]) и аналогичные конструкции. Это приводит к нескольким изменениям в практике кодирования, включая использование JSON.parse () вместо eval() для анализа данных JSON.
Подобно unsafe-inline, вы можете использовать ключевое слово unsafe-eval, чтобы разрешить запуск кода для некоторых или всех источников. Опять же, это противоречит лучшей практике для современного кода и должно использоваться только для устаревшего кода, который не может быть реорганизован.
Nonces и Hashes чтобы разрешить встроенные скрипты
Если вам абсолютно необходимо сделать исключение для некоторого унаследованного встроенного кода, который нельзя перенести в отдельный файл, CSP предоставляет две функции, позволяющие разрешать определенные блоки кода, не прибегая к unsafe-inline. Для внесения в белый список определенного фрагмента кода вы можете использовать nonce (одноразовый) номер (уникальный одноразовый идентификатор) для тега
Чтобы разрешить этот конкретный тег сценария, используйте:
Генерация nonce номера для каждой загрузки страницы может быть проблематичным, поэтому другой подход заключается в использовании криптографического хэша самого разрешенного кода. Для этого начните с вычисления хэша SHA для всех символов внутри тега
Тогда директива, использующая хэш SHA256 этого кода:
Директивы CSP на уровне страницы
Помимо источников контента, внесенных в белый список, CSP также может налагать ограничения на действия, которые может выполнять текущая страница. Чтобы использовать эту функцию, используйте директиву sandbox, чтобы обрабатывать страницу так, как если бы она находилась внутри изолированного фрейма. Полное описание ограничений, накладываемых песочницей на страницу, см. в разделе Sandboxing в спецификации HTML5.
Чтобы повысить безопасность старых сайтов с большим количеством устаревших HTTP-страниц, вы можете использовать директиву upgrade-insecure-requests для перезаписи небезопасных URL-адресов. Это дает указание агентам пользователя изменять HTTP на HTTPS в схемах URL-адресов и может иметь неоценимое значение, если у вас все еще есть несколько URL-адресов HTTP.
Политика тестирования и мониторинг нарушений
Политика безопасности контента предоставляет мощные функциональные возможности для контроля источников контента и поведения страниц. Однако это также означает, что одна неправильно настроенная директива может сделать сайт частично или полностью недоступным для посетителей, поэтому вам нужен способ безопасного тестирования директив.
Прежде чем начать работу с директивами CSP, вы можете использовать заголовок Content-Security-Policy-Report-Only вместо Content-Security-Policy. В режиме report-only браузер будет отслеживать политику и сообщать о нарушениях, но фактически не применяет ограничения. Используйте директиву report-uri, чтобы сообщить браузеру, где он должен публиковать отчеты о нарушениях в формате JSON. Это может быть любой локальный или внешний URI, например:
Обратите внимание, что вы можете комбинировать заголовки Content-Security-Policy-Report-Only и Content-Security-Policy, чтобы протестировать новую политику, при этом применяя существующую.
После того, как политика активна, вы можете использовать ту же директиву report-uri для получения подробных отчетов о нарушениях политики. Каждый отчет JSON начинается с атрибута csp-report и выглядит примерно так:
Как видите, отчеты предоставляют информацию о каждом нарушении политики, включая заблокированный URI и нарушенную директиву. Это значительно упрощает устранение неполадок, особенно для политик с сотнями директив и значений.
Поддержка Content Security Policy в Netsparker
В течение последних нескольких лет CSP Level 2 был реализован во всех современных браузерах и широко используется в Интернете как эффективный способ снижения риска XSS. Чтобы отразить это, Netsparker проверяет наличие HTTP-заголовков Content-Security-Policy и сообщает об уязвимости «Best Practice», если они отсутствуют.
Однако простого наличия заголовка CSP недостаточно, поскольку недопустимые директивы будут игнорироваться браузерами (и, следовательно, неэффективны), в то время как небезопасные значения директив не обеспечат ожидаемый уровень защиты. Netsparker выполняет более 20 подробных проверок, чтобы убедиться, что директивы используют правильный синтаксис в сочетании со значениями, обеспечивающими эффективную безопасность. См. Vulnerability Index для получения полного списка проверок CSP, доступных в Netsparker.
Демонстрация Content Security Policy в действии
И, наконец, для практической демонстрации настройки заголовков CSP посмотрите это еженедельное интервью по безопасности с исследователем безопасности Netsparker Свеном Моргенротом. Разговаривая с Полом Асадуряном, Свен рассказывает о проблемах, которые CSP предназначен для решения, и показывает практическую демонстрацию заголовков CSP в действии.
Настройка Content Security Policy на сайте
Эта информация не нужна обычным пользователям компьютера, но будет полезна для людей, занимающихся разработкой и администрированием сайтов. Как известно страницы сайта состоят из различных ресурсов, таких как скрипты, таблицы стилей, изображения, шрифты и так далее. Они могут загружаться как непосредственно с сервера, где расположен сам сайт, так и с любого другого домена в интернете. Это имеет свои преимущества и недостатки.
Серьезным минусом загрузки ресурсов из другого источника является потенциальная уязвимость внедрения вредоносного контента. Например, в виде межсайтовых скриптовых атак или на английском Cross Site Scripting (XSS) и внедрения зловредных данных. Браузер, загружая страницу доверяет всему контенту, который на ней присутствует, даже если это зловредный код, внедренный незаконно.
Он просто не может отличить один от другого. Как защитить сайт от атак злоумышленников с использованием XSS посвящена данная статья. Для решения подобного рода проблем и повышения безопасности веб-приложений был разработан специальный защитный механизм, подсказывающий браузеру какой контент является незаконным на данной странице.
Content Security Policy (CSP) — это политика безопасности контента устанавливаемая администратором сайта и в декларативной форме с помощью HTTP-заголовка уведомляющая посетителей о доверенных источниках (белых списках) откуда могут быть загружены ресурсы для данной страницы. Это позволяет браузеру клиента блокировать загрузку ресурсов из не доверенных источников, а разработчику получать отчеты о попытках нарушения установленной политики безопасности.
Другими словами, сервер только информирует о перечне доверенных источников и типах ресурсов на данной странице, а исполнение данных рекомендаций лежит полностью на клиентском ПО. Поэтому требуется поддержка данной технологии в браузере, с чем как всегда все не совсем гладко.
На сегодняшний день рекомендацией консорциума W3C является CSP Level 2 которую мы будем рассматривать. Идет работа над Level 3 пока имеющей статус рабочего проекта. Для информирования клиента об использовании политики безопасности контента служит HTTP заголовок Content-Security-Policy который может принимать различные директивы для управления загрузкой ресурсов. Если браузер не поддерживает эту возможность, то он просто игнорируется.
В заголовке перечисляются разрешенные URL для каждого типа контента отдельно. Поэтому даже если злоумышленник сможет внедрить свой код на страницу с домена evil.ru, то он не будет выполнен, если в директиве будет указано использовать только собственный домен.
Правила формирования заголовка
Что такое Content Security Policy мы выяснили, способы добавления на сайт мы рассмотрим позже, а сейчас займемся самим заголовком. Главное правило, которое нужно запомнить. Запрещено все, что не разрешено в директиве в явном виде.
Заголовок должен соответствовать следующему формату. Название заголовка отделяется двоеточием, значения директив (directive) пишутся через пробел, директивы отделяются друг от друга точкой с запятой. Наследование не применяется, каждая директива должна содержать свой «белый список» разрешенных значений.
Имеются специальные ключевые слова, которые записываются в одинарных кавычках.
Директивы Content Security Policy
CSP предоставляет широкий набор директив для разных случаев использования и они являются регистронезависимыми.
default-src — устанавливает значение по умолчанию для других директив, если они не заданы в явном виде. Рассмотрим несколько примеров.
Любые внешние ресурсы могут загружаться только с текущего домена, но запрещены встроенные, динамические, data: и остальные.
Любые ресурсы могут загружаться из любых источников. Не распространяется на встроенные и динамически добавляемые ресурсы.
Дополнительно разрешает инлайн и динамически подключаемые ресурсы.
Устанавливает для всех директив значение по умолчанию «нет», в результате все ресурсы страницы окажутся заблокированными и загрузится только html документ. Рекомендуется использовать, чтобы затем прописать правила только для тех ресурсов, которые реально используются на сайте.
Задает для всех ресурсов необходимость использования HTTPS протокола, все что подключается с использованием обычного HTTP загружено не будет.
script-src — задает разрешенный список источников контента для внешних скриптов JavaScript и других сценариев наподобие таблиц стилей XSLT.
Чтобы это исправить это нужно прямо разрешить свой домен для загрузки JavaScript.
Разрешает загрузку ресурсов из любого источника, но скрипты разрешены только с текущего хоста, site.ru и файл main.js расположенный по адресу example.ru/scripts/main.js
Смысл в том, что сервер каждый раз при запросе страницы генерирует ее заново и подставляет в заголовок Content-Security-Policy, одновременно добавляя в качестве значения атрибута nonce в тег скрипта. Это можно использовать как с внешними, так и со встроенными скриптами.
Браузер сверяет значение из заголовка со значением, указанным в тэге скрипта и если они не совпадают или в скрипте он отсутствует, то такие сценарии блокируются. Поэтому в приведенном далее примере исполнится только второй и четвертый сценарии, хотя домен any.ru в правилах явно не указан. Использование ‘unsafe-inline’ заметно снижает эффективность CSP, поэтому в целях безопасности одноразовое значение должно быть трудно подбираемым. В связи с чем рекомендуется использование криптографически стойкого генератора случайных чисел для его создания.
Альтернативным вариантом для встроенных сценариев является использование их хэша. Он обеспечивает большую надежность, однако сильнее нагружает браузер. Для этого вычисляется хэш кода, расположенного между тегами по алгоритму SHA-256, SHA-384 или SHA-512 и затем кодируется с помощью base64. Получившейся результат добавляется в заголовок с указанием использованного алгоритма хеширования. Так для сценария alert(‘Привет мир!’); это выглядит так.
Браузер вычисляет хэш встроенного сценария на странице и если он совпадает со значением из заголовка, то сценарий выполняется. Стоит помнить, что для хэша имеют значение любые символы, в том числе и пробелы. Поэтому исполнится только первый из следующих вариантов, несмотря на то что сам код идентичен.
Стили могут дополнительно загружаться из папки site.ru/catalog/css и ее подпапок только по защищенному протоколу, все остальное только с собственного домена, так же разрешены встроенные сценарии.
connect-src — адреса с которыми может устанавливаться соединение с помощью интерфейсов JavaScript. Под ее действие попадают XMLHttpRequest, WebSocket, EventSource и подобное.
font-src — регламентирует разрешенные источники загрузки шрифтов. Например, если в директиве default-src задан собственный домен, а ваш сайт загружает веб-шрифты с сервиса google, то необходимо явно разрешить загрузку из внешнего источника.
base-uri — ограничивает URL которые могут использоваться для указания базового адреса в теге документа.
form-action — регламентирует адреса, на которые могут быть отправлены формы на странице.
img-src — список разрешенных источников для загрузки изображений. Изображения, встраиваемые в страницу с помощью data, нужно разрешать отдельно.
Допустимы изображения только с собственного домена, остальное с любого адреса по защищенному протоколу.
Запрещены любые изображения в том числе со своего хоста, но разрешены подключенные через data
media-src — регулирует источники аудио, видео и связанных текстовых данных.
object-src — указывает возможные источники для загрузки плагинов на страницу.
plugin-types — регулирует разрешенный тип встраиваемых плагинов на основе их MIME типа. Например, разрешает только использование Flash.
Если на странице http://site.ru/example будет обнаружено нарушение политики безопасности контента, то на адрес http://site.ru/csp-error будет отправлен отчет о каждой попытке нарушения отдельно. Соответственно по этому адресу должен располагаться скрипт, который будет обрабатывать поступающую информацию. Вид отчета зависит от типа нарушения, это пример для встроенного скрипта.
sandbox — помещает страницу в песочницу и определяет разрешенные действия, используются такие же флаги как и для iframe.
Мы рассмотрели возможности имеющиеся в CSP Level 2 по защите сайта от Cross Site Scripting и подмены контента. Несмотря на очевидные преимущества он не используется в интернете на сегодняшний день достаточно широко. Этому есть простое объяснение. Для его внедрения нужно приложить много усилий и зачастую переписать часть кода для обеспечения надлежащего уровня защиты.
Все относительно просто, когда для загрузки ресурсов используется только собственный домен или несколько заранее известных сторонних адресов. Среднестатистический сайт в интернете использует счетчики посещаемости, различные рекламные сети и виджеты. Все это тянет за собой шлейф из десятков дополнительно загружаемых на страницу ресурсов с самых разных URL зачастую неизвестных заранее.
В этой ситуации настройка становится совсем не тривиальной задачей. Однако даже в этом случае, политика безопасности контента может найти свое применение, например для защиты административной части сайта, страницы оплаты или других важных разделов. Это поможет создать дополнительный барьер от кражи сессий, паролей и другой конфиденциальной информации.
Стоит иметь в виду, что антивирусы могут вмешиваться в работу сайта. Например, Касперский встраивает в страницу собственный скрипт для ее проверки, поэтому когда он обнаруживает в ответе сервера этот заголовок, то он его модернизирует на лету и добавляет правила разрешающие ему выполняться на странице, чтобы браузер его не заблокировал.
Заголовок Content-Security-Policy-Report-Only
Данный заголовок аналогичен предыдущему, с той лишь разницей, что он не блокирует загрузку ресурсов, а только информирует о факте нарушения политики безопасности контента.
Его удобно использовать для отладки политики и сбора статистики. Может применяться на рабочем сайте, так как ничем не выдает свое присутствие для простых посетителей и не создает им проблем. В случае обнаружения нарушений безопасности в консоли будут выводиться соответствующие сообщения, а если указана директива report-uri, то по указанному адресу будет высылаться отчет. При этом нужно учитывать, что при высокой посещаемости сайта поток отчетов может быть высоким.
Как добавить HTML-заголовок на страницу
Здесь все аналогично другим HTTP заголовкам и существует множество вариантов, как это можно сделать. Вот некоторые из них, но помните, что в идеале для каждой страницы сайта должен быть свой набор правил чтобы свести площадь атаки к минимуму.
Сервер Apache, конфигурационный файл httpd.conf
Сервер Nginx, конфигурационный файл nginx.conf
HTML метатег meta добавляется в head страницы. Данный тег не действует на ресурсы, расположенные на странице перед ним. Не может использоваться для Content-Security-Policy-Report-Only
Что делать, если вы не добавляли данный заголовок, но получаете ошибки в консоли связанные с CSP. Значит он добавляется автоматически сервером, CMS или плагином. Нужно найти источник его появления и отключить его вывод или настроить нужным вам образом. Если такой возможно нет, то можно попробовать его переопределить, добавив собственный с нужными настройками.
Content Security Policy — опасная политика
Обзор нового веб-стандарта и его фундаментальных уязвимостей
Чтобы идти в ногу со временем, браузеры внедряют все новые технологии для обеспечения безопасности пользователей. Одна из них — Content Security Policy, позволяющая разработчикам сайтов четко объяснить браузеру, на какие адреса тот может выполнять межсайтовые запросы. Однако новый веб-стандарт страдает от существенных недостатков, ставящих под сомнение его пригодность как защиты от XSS.
Content Security Policy vs Same Origin Policy
Одним из главных принципов безопасности браузеров и веба в целом является Same Origin Policy — дословно «политика единого источника» (устоявшегося термина до сих пор не существует). Ее суть заключается в проверке трех компонентов, из которых состоит origin: протокол, хост и порт. Если страница http://test1.ru/a.html пытается получить доступ к DOM страницы http://test2.ru/b.html, то у нее ничего не выйдет, так как хосты отличаются. Если бы SOP не существовал, любой сайт мог бы делать запросы на произвольные адреса и получать оттуда данные, что, как подсказывает логика, не есть хорошо. Причем страдали бы все: как пользователи, чьи персональные данные летали бы без принуждения, так и владельцы ресурсов, — в общем, в вебах творился бы полный хаос. Поэтому Same Origin Policy всех спасает и все счастливы. Однако есть одно но: что, если на страницу http://test1.ru/a.html внедрен злой скрипт с сайта http://test2.ru/, который делает плохие штуки в контексте браузера жертвы? В данном случае SOP бесполезен, ибо на
Очевидно, что такой подход не поможет защититься от случаев, когда у атакующего есть возможность внедрить код в скрипт с валидным токеном. Кроме того, есть масса вариантов обхода, о чем пойдет речь ниже.
CRLF Injection
При наличии CRLF-инъекции в заголовках ответа, то есть отсутствии фильтрации символа переноса строки, у атакующего есть возможность банального обхода CSP с помощью внедрения собственных директив. Здесь большую роль играет то, какой заголовок браузер будет использовать при наличии нескольких с одинаковым именем. Как в случае с HTTP Parameter Pollution, где одинаковые имена параметров обрабатываются по-разному на разных платформах, при внедрении еще одного заголовка Content-Security-Policy важно, где он окажется — перед первоначальным или после него, так как один браузер может взять последний заголовок, а другой — первый. Так, если браузер отдает приоритет первому и мы внедряем наш CSP перед настоящим, то обход тривиален:
Если же используется последний встреченный заголовок, то мы можем отправить его в тело страницы, отправив rnrn:
Таким образом, первоначальный заголовок попадет в содержание HTTP-ответа и не будет иметь силы.
Scriptless Attacks
Перейдем к более интересным вариантам обхода — на стороне клиента. Основная цель межсайтового скриптинга — получить некую приватную информацию пользователя, которая обычно хранится в cookie. Однако с введением таких мер защиты, как флаг httpOnly, запрещающий JS-скриптам доступ к защищаемым cookie, внедрением в браузеры XSS-фильтров (XSS Auditor в Chrome, XSSFilter в IE), собственно и самого CSP, исследователи безопасности все чаще обращают внимание на другие цели, например личные данные, различного рода токены (CSRF, oAuth, в скором будущем и script-nonce). При этом используются новые способы отправки данных на сторонние сайты, без JavaScript!
CSSAR
Еще в 2008 году Эдуардо Вела (Eduardo Vela), Дэвид Линдсей (David Lindsay) и Гарет Хейс (Gareth Heyes) представили технику чтения атрибутов тегов с помощью CSS-селекторов. На данный момент техника все так же актуальна. Если раньше она позиционировалась как обход NoScript, то сейчас ее можно использовать и для CSP. Суть CSSAR (CSS Attribute Reading) в брутфорсе значений с помощью селекторов атрибутов. Для этого на уязвимую страницу подключается CSS-файл с комбинациями выражений:
Если значение целевого инпута начинается с «a», то будет отправлен запрос на сайт атакующего через подгрузку фонового изображения, относящегося к соответствующей комбинации символов. CSS не имеет возможности указать позицию символа, поэтому для получения следующего знака необходимо сгенерировать массу вариантов вида
Поэтому конечный PoC может иметь объем в несколько сотен килобайтов.
CSSAR в действии
Вариант обхода № 4. Postcards from post-XSS world
Интересные идеи предложил Михал Залевски (Michal Zalewski). Например, имея внедрение кода перед формой, защищенной CSRF-токеном, можно вставить незакрытый тег img:
Все содержание страницы до следующей закрывающей кавычки, включая и целевой токен, после незакрытого атрибута src будет отправлено на сайт атакующего.