Автор выбрал Девушки, которые программируют для получения пожертвования в рамках программы Напиши для благотворительности.
Введение
Когда вы посещаете веб-сайт, для его загрузки и отображения используются различные ресурсы. Например, когда вы заходите на https://www.digitalocean.com
, ваш браузер загружает HTML и CSS напрямую с digitalocean.com
. Однако изображения и другие ресурсы загружаются с assets.digitalocean.com
, а скрипты аналитики загружаются с их соответствующих доменов.
Некоторые веб-сайты используют множество различных служб, стилей и скриптов для загрузки и отображения своего контента, и ваш браузер будет выполнять все это. Браузер не знает, является ли код вредоносным, поэтому ответственность за защиту пользователей лежит на разработчике. Поскольку на веб-сайте может быть много ресурсов, наличие функции в браузере, которая разрешает только одобренные ресурсы, является хорошим способом гарантировать, что пользователи не подвергнутся компрометации. Для этого и служат политики безопасности контента (CSP).
С использованием заголовка CSP разработчик может явно разрешить выполнение определенных ресурсов, предотвращая выполнение всех остальных. Поскольку на большинстве сайтов может быть более сотни ресурсов, и каждый из них должен быть одобрен для конкретной категории ресурсов, внедрение CSP может быть утомительной задачей. Однако веб-сайт с CSP будет более безопасным, поскольку он гарантирует, что разрешено выполнять только одобренные ресурсы.
В этом учебнике вы научитесь реализовывать CSP в базовом приложении Django. Вы настроите CSP, чтобы разрешить выполнение определенных доменов и встроенных ресурсов. По желанию, вы также можете использовать Sentry для регистрации нарушений.
Предварительные требования
Для завершения этого учебника вам понадобятся:
- A working Django project (version 3 or greater is preferred), either on your local machine or a DigitalOcean Droplet. If you don’t have one, you can create one with the tutorial, How to Install Django and Set Up a Development Environment on Ubuntu 20.04.
- A web browser like Firefox or Chrome and an understanding of browser network tools. For more on using browser network tools, check out the product documentation for the Network Monitor in Firefox or the DevTools Network Tab in Chrome. For more general guidance on browser developer tools, see the guide: What are Browser Developer Tools?
- Знания Python 3 и Django, которые вы можете получить из серии учебников Как программировать на Python и Разработка с Django.
- Учетная запись на Sentry для отслеживания нарушений CSP (по желанию).
Шаг 1 — Создание демонстрационного представления
На этом этапе вы измените способ обработки представлений вашим приложением, чтобы добавить поддержку CSP.
Как предварительное условие, вы установили Django и настроили примерный проект. Стандартное представление в Django слишком простое, чтобы продемонстрировать все возможности промежуточного ПО CSP, поэтому вы создадите простую HTML-страницу для этого учебника.
Перейдите в папку проекта, которую вы создали в предварительных требованиях:
Во время нахождения в директории django-apps
создайте своё виртуальное окружение. Мы назовем его общим именем env
, но вы можете использовать имя, которое имеет смысл для вас и вашего проекта.
Теперь активируйте виртуальное окружение с помощью следующей команды:
Внутри виртуального окружения создайте файл views.py
в папке вашего проекта с использованием nano
или вашего любимого текстового редактора:
Теперь добавьте базовый вид, который будет отображать шаблон index.html
, который вы создадите далее. Добавьте следующее в views.py
:
Сохраните и закройте файл, когда закончите.
Создайте шаблон index.html
в новой директории templates
:
Добавьте следующее в index.html
:
Созданный нами вид будет отображать эту простую HTML-страницу. Он будет отображать текст Привет, Сэмми! вместе с изображением Сэмми Акулы.
Сохраните и закройте файл, когда закончите.
Для доступа к этому виду вам нужно обновить urls.py
:
Импортируйте файл views.py
и добавьте новый маршрут, добавив выделенные строки:
Новый вид, который вы только что создали, теперь будет доступен при посещении /
(когда приложение запущено).
Сохраните и закройте файл.
Наконец, вам нужно обновить INSTALLED_APPS
, чтобы включить testsite
в settings.py
:
Здесь вы добавляете testsite
в список приложений в settings.py
, чтобы Django мог делать некоторые предположения о структуре вашего проекта. В этом случае он будет предполагать, что папка templates
содержит шаблоны Django, которые вы можете использовать для отображения представлений.
Из корневого каталога проекта (testsite
) запустите сервер разработки Django с помощью следующей команды, заменив your-server-ip
на IP-адрес вашего собственного сервера.
Откройте браузер и перейдите по адресу your-server-ip:8000
. Страница должна выглядеть примерно так:
На этом этапе страница отображает изображение профиля Сэмми Акулы. Под изображением находится текст Привет, Сэмми! синим шрифтом.
Чтобы остановить сервер разработки Django, нажмите CONTROL-C
.
На этом этапе вы создали базовое представление, которое выступает в качестве домашней страницы вашего проекта Django. Далее вы добавите поддержку CSP в ваше приложение.
Шаг 2 — Установка промежуточного ПО CSP
На этом этапе вы установите и реализуете промежуточное ПО CSP, чтобы добавлять заголовки CSP и работать с функциями CSP в ваших представлениях. Промежуточное ПО добавляет дополнительную функциональность к любому запросу или ответу, который обрабатывает Django. В данном случае, промежуточное ПО Django-CSP добавляет поддержку CSP к ответам Django.
Сначала установите промежуточное программное обеспечение CSP Mozilla в свой проект Django с помощью pip
, менеджера пакетов Python. Используйте следующую команду для установки необходимого пакета из PyPi, индекса пакетов Python. Чтобы выполнить команду, вы можете либо остановить сервер разработки Django, используя CONTROL-C
, либо открыть новую вкладку в вашем терминале:
Затем добавьте промежуточное программное обеспечение в настройки вашего проекта Django. Откройте settings.py
:
С установленным django-csp
теперь можно добавить промежуточное программное обеспечение в settings.py
. Это добавит заголовки CSP к вашим ответам.
Добавьте следующую строку в массив конфигурации MIDDLEWARE
:
Сохраните и закройте файл, когда закончите. Ваш проект Django теперь поддерживает CSP. В следующем шаге вы начнете добавлять заголовки CSP.
Шаг 3 — Внедрение заголовка CSP
Теперь, когда ваш проект поддерживает CSP, он готов к усилению безопасности. Для этого вы настроите проект на добавление заголовков CSP к вашим ответам. Заголовок CSP сообщает браузеру, как вести себя при обнаружении определенного типа контента. Таким образом, если в заголовке указано разрешить только изображения с определенного домена, то браузер разрешит только изображения с этого домена.
Используя nano или ваш текстовый редактор, откройте settings.py
:
Определите следующие переменные в любом месте файла:
Эти правила являются шаблоном для вашей CSP. Эти строки указывают, какие источники разрешены для изображений, таблиц стилей и скриптов соответственно. В настоящее время они все содержат строку 'self'
, что означает, что разрешены только ресурсы с вашего собственного домена.
Сохраните и закройте файл, когда закончите.
Запустите свой проект Django с помощью следующей команды:
Когда вы посетите IP-адрес вашего сервера:8000
, вы увидите, что сайт сломан:
Как и ожидалось, изображение не появляется, и текст отображается в стандартном стиле (жирный черный). Это означает, что заголовок CSP применяется, и наша страница теперь более безопасна. Поскольку представление, которое вы создали ранее, ссылается на таблицы стилей и изображения с доменов, не принадлежащих вам, браузер блокирует их.
Ваш проект теперь имеет работающую CSP, которая указывает браузеру блокировать ресурсы, не принадлежащие вашему домену. Далее вы измените CSP, чтобы разрешить конкретные ресурсы, что исправит отсутствие изображения и стилей на главной странице.
Шаг 4 — Изменение CSP для разрешения внешних ресурсов
Теперь, когда у вас есть базовая CSP, вы будете ее изменять в зависимости от того, что используется на вашем сайте. Например, сайт, который использует шрифты Adobe и встроенные видеоролики YouTube, должен разрешить эти ресурсы. Однако, если ваш сайт отображает только изображения с вашего собственного домена, вы можете оставить настройки изображений по умолчанию в ограничительном режиме.
Первый шаг – найти каждый ресурс, который вам необходимо утвердить. Вы можете использовать инструменты разработчика вашего браузера для этого. Откройте Монитор сети в Инструментах разработчика, обновите страницу и посмотрите заблокированные ресурсы:
В журнале сети показано, что два ресурса блокируются CSP: таблица стилей с сайта fonts.googleapis.com и изображение с сайта html.sammy-codes.com. Чтобы разрешить эти ресурсы в заголовке CSP, вам нужно изменить переменные в файле settings.py.
Чтобы разрешить ресурсы с внешних доменов, добавьте домен в часть CSP, которая соответствует типу файла. Так, чтобы разрешить изображение с сайта html.sammy-codes.com, вы добавите html.sammy-codes.com в CSP_STYLE_SRC.
Откройте файл settings.py и добавьте следующее в переменную CSP_STYLE_SRC:
Теперь, вместо того чтобы разрешать только изображения с вашего домена, сайт также разрешает изображения с html.sammy-codes.com.
Представление индекса использует шрифты Google. Google предоставляет вашему сайту шрифты (с https://fonts.gstatic.com
) и таблицу стилей для их применения (с https://fonts.googleapis.com
). Чтобы разрешить загрузку шрифтов, добавьте следующее в вашу CSP:
Аналогично разрешению изображений с html.sammy-codes.com
, вы также разрешите таблицы стилей с fonts.googleapis.com
и шрифты с fonts.gstatic.com
. Для контекста, таблица стилей, загруженная с fonts.googleapis.com
, используется для применения шрифтов. Сами шрифты загружаются с fonts.gstatic.com
.
Сохраните и закройте файл.
Предупреждение: Подобно self
, существуют другие ключевые слова, такие как unsafe-inline
, unsafe-eval
или unsafe-hashes
, которые могут использоваться в CSP. Настоятельно рекомендуется избегать использования этих правил в вашем CSP. Хотя они облегчат реализацию, они могут быть использованы для обхода CSP и сделать его бесполезным.
Дополнительную информацию смотрите в документации продукта Mozilla для “Небезопасного встроенного сценария”.
Теперь шрифты Google будут разрешены для загрузки стилей и шрифтов на вашем сайте, а html.sammy-codes.com
будет разрешено загружать изображения. Однако, когда вы посещаете страницу на своем сервере, вы можете заметить, что теперь загружаются только изображения. Это происходит потому, что встроенные стили в HTML, которые используются для применения шрифтов, не разрешены. Вы исправите это на следующем шаге.
Шаг 5 — Работа с встроенными скриптами и стилями
На данном этапе вы изменили CSP, чтобы разрешить внешние ресурсы. Однако встроенные ресурсы, такие как стили и скрипты в вашем представлении, все еще не разрешены. На этом этапе вы настроите их работу, чтобы применить стили шрифтов.
Существует два способа разрешения встроенных скриптов и стилей: через nonce и хэши. Если вы часто изменяете встроенные скрипты и стили, используйте nonce, чтобы избежать частых изменений в вашем CSP. Если вы редко обновляете встроенные скрипты и стили, использование хэшей является разумным подходом.
Использование nonce
для разрешения встроенных скриптов
Сначала вы используете подход через nonce. Nonce – это случайно сгенерированный токен, который уникален для каждого запроса. Если два человека посещают ваш сайт, они получат уникальный nonce
, который встраивается в разрешенные вами встроенные скрипты и стили. Представьте nonce как одноразовый пароль, который одобряет выполнение определенных частей сайта в течение одной сессии.
Чтобы добавить поддержку nonce в ваш проект, вы обновите свой CSP в файле settings.py
. Откройте файл для редактирования:
Добавьте script-src
в CSP_INCLUDE_NONCE_IN
в файле settings.py
.
Определите CSP_INCLUDE_NONCE_IN
в любом месте файла и добавьте 'script-src'
к нему:
CSP_INCLUDE_NONCE_IN
указывает, к каким встроенным скриптам разрешено добавлять атрибуты nonce
. CSP_INCLUDE_NONCE_IN
обрабатывается как массив, так как несколько источников данных поддерживают нонсы (например, style-src
).
Сохраните и закройте файл.
Теперь разрешено генерировать нонсы для встроенных скриптов, когда вы добавляете к ним атрибут nonce
в вашем шаблоне представления. Чтобы попробовать это, вы используете простой фрагмент JavaScript.
Откройте index.html
для редактирования:
Добавьте следующий фрагмент в <head>
HTML:
Этот фрагмент выводит Hello from the console!"
в консоль браузера. Однако, поскольку в вашем проекте установлена CSP, которая разрешает только встроенные скрипты, если у них есть nonce
, этот скрипт не будет выполняться и вместо этого будет генерироваться ошибка.
Вы можете увидеть эту ошибку в консоли вашего браузера при обновлении страницы:
Изображение загружается, потому что вы разрешили внешние ресурсы на предыдущем этапе. Как и ожидалось, стили в настоящее время являются стандартными, потому что вы еще не разрешили встроенные стили. Также как и ожидалось, сообщение в консоли не было напечатано и вернуло ошибку. Вам нужно будет дать ему nonce
, чтобы одобрить его.
Вы можете сделать это, добавив nonce="{{request.csp_nonce}}"
в этот скрипт как атрибут. Откройте index.html
для редактирования и добавьте выделенную часть, как показано здесь:
Сохраните и закройте файл после завершения работы.
Если обновите страницу, скрипт теперь будет выполняться:
Когда вы посмотрите в Просмотреть элемент, вы заметите, что значение атрибута отсутствует:
Значение не отображается по соображениям безопасности. Браузер уже обработал значение. Оно скрыто, чтобы любые скрипты с доступом к DOM не могли получить к нему доступ и применить его к какому-либо другому скрипту. Если вы вместо этого Просмотреть исходный код страницы, вот что получил браузер:
Обратите внимание, что каждый раз при обновлении страницы значение nonce
меняется. Это потому, что промежуточное ПО CSP в нашем проекте генерирует новый nonce
для каждого запроса.
Эти значения nonce
добавляются к заголовку CSP, когда браузер получает ответ:
Каждый запрос, который браузер отправляет на ваш сайт, будет иметь уникальное значение nonce
для этого скрипта. Поскольку nonce
предоставляется в заголовке CSP, это означает, что сервер Django утвердил выполнение этого конкретного скрипта.
Вы обновили свой проект для работы с nonce, который может быть применен к нескольким ресурсам. Например, вы можете применить его и к стилям, обновив CSP_INCLUDE_NONCE_IN
для разрешения style-src
. Но есть более простой способ утверждения встроенных ресурсов, и это то, что вы сделаете далее.
Использование Хэшей для Разрешения Встроенных Стилей
Другой подход для разрешения встроенных скриптов и стилей – использование хэшей. Хэш – это уникальный идентификатор для определенного встроенного ресурса.
В качестве примера, это встроенный стиль в нашем шаблоне:
В настоящее время стили не работают. Когда вы просматриваете сайт в браузере, изображения успешно загружаются, но шрифты и стили не применяются:
В консоли браузера вы найдете ошибку, что встроенный стиль нарушает CSP. (Могут быть и другие ошибки, но ищите ошибку относительно встроенного стиля.)
Ошибка возникает потому, что стиль не одобрен нашим CSP. Однако обратите внимание, что ошибка предоставляет хэш, необходимый для одобрения фрагмента стиля. Этот хэш уникален для этого конкретного фрагмента стиля. Ни один другой фрагмент никогда не будет иметь такой же хэш. Когда этот хэш размещается внутри CSP, каждый раз, когда загружается этот конкретный стиль, он будет одобрен. Но если вы когда-либо измените эти стили, вам нужно будет получить новый хэш и заменить им старый в CSP.
Теперь вы примените хэш, добавив его в CSP_STYLE_SRC
в settings.py
, таким образом:
Добавление хэша sha256-...
в список CSP_STYLE_SRC
позволит браузеру загружать таблицу стилей без ошибок.
Сохраните и закройте файл.
Теперь перезагрузите сайт в браузере, и шрифты и стили должны успешно загрузиться:
Встроенные стили и скрипты теперь функционируют корректно. На этом этапе вы использовали два различных подхода, нонсы и хеши, чтобы разрешить встроенные стили и скрипты.
Однако существует важная проблема, которую нужно решить. Политики безопасности содержимого (CSP) трудно поддерживать, особенно для крупных веб-сайтов. Вам может понадобиться способ отслеживать, когда CSP блокирует ресурс, чтобы вы могли определить, является ли он вредоносным ресурсом или просто сломанной частью вашего сайта. На следующем этапе вы будете использовать Sentry для журналирования и отслеживания всех нарушений, вызванных вашим CSP.
Шаг 6 — Сообщение о нарушениях с помощью Sentry (дополнительно)
Учитывая то, насколько строги бывают CSP, полезно знать, когда он блокирует контент — особенно поскольку блокировка контента, вероятно, означает, что некоторая функциональность на вашем сайте не будет работать. Инструменты, такие как Sentry, могут сообщить вам, когда CSP блокирует запросы для пользователей. На этом этапе вы настроите Sentry для журналирования и отчетности о нарушениях CSP.
В качестве предварительного условия вы зарегистрировались на сайте Sentry. Теперь вы создадите проект.
В левом верхнем углу панели управления Sentry щелкните вкладку Проекты:
В правом верхнем углу нажмите кнопку Создать проект:
Вы увидите ряд логотипов с заголовком, указывающим Выберите платформу. Выберите Django:
Затем, внизу, назовите свой проект (для этого примера мы используем sammys-tutorial
) и нажмите кнопку Create Project:
Sentry предоставит вам фрагмент кода, который нужно добавить в ваш файл settings.py
. Сохраните этот фрагмент, чтобы добавить его на следующем этапе.
В вашем терминале установите SDK Sentry:
Откройте settings.py
следующим образом:
Добавьте следующее в конец файла и убедитесь, что заменили SENTRY_DSN
на значение из панели управления:
Этот код предоставлен Sentry, чтобы он мог записывать любые ошибки, возникающие в вашем приложении. Это настройка Sentry по умолчанию и инициализирует Sentry для регистрации проблем на нашем сервере. Технически вам не нужно инициализировать Sentry на вашем сервере для нарушений CSP, но в редком случае возникновения проблем с рендерингом nonce или хешей, эти ошибки будут зарегистрированы в Sentry.
Сохраните и закройте файл.
Затем вернитесь на панель управления вашим проектом и нажмите на значок шестеренки, чтобы перейти в Настройки:
Перейдите на вкладку Заголовки безопасности:
Скопируйте report-uri
:
Добавьте его в вашу политику безопасности контента (CSP) следующим образом:
Убедитесь, что заменили your-report-uri
значением, скопированным с панели управления.
Сохраните и закройте файл. Теперь, когда применение CSP вызывает нарушение, Sentry зарегистрирует его по этому URI. Вы можете проверить это, удалив домен или хеш из вашей CSP, или удалив nonce
из скрипта, который вы добавили ранее. Загрузите страницу в браузере, и вы увидите ошибку на странице Проблемы Sentry:
Если вы обнаружите, что количество журналов становится слишком большим, вы также можете определить
CSP_REPORT_PERCENTAGE
в файле settings.py
, чтобы отправлять в Sentry только определенный процент журналов.
Теперь, когда происходит нарушение CSP, вы получите уведомление и сможете просмотреть ошибку в Sentry.
Заключение
В этой статье вы защитили ваше приложение Django с помощью политики безопасности контента. Вы обновили свою политику, чтобы разрешить внешние ресурсы, и используете уникальные значения (nonces) и хеши для разрешения встроенных скриптов и стилей. Вы также настроили ее на отправку нарушений в Sentry. В качестве следующего шага изучите документацию Django CSP, чтобы узнать больше о том, как обеспечить выполнение вашей CSP.