Безопасность в Django¶
Этот документ рассматривает возможности Django с точки зрения безопасности. В документе приведены советы по защите сайтов, созданных с помощью Django.
Защита от межсайтового скриптинга (XSS)¶
XSS-атаки позволяют пользователю внедрять клиентские сценарии в браузеры других пользователей. Обычно это достигается путем хранения вредоносных сценариев в базе данных, откуда они будут извлекаться и отображаться другим пользователям, или путем предложения пользователям щелкнуть ссылку, которая приведет к выполнению JavaScript злоумышленника браузером пользователя. Однако XSS-атаки могут исходить из любого ненадежного источника данных, например файлов cookie или веб-служб, если данные не проходят достаточную очистку перед включением на страницу.
Использование шаблонов Django защищает вас от большинства XSS атак. Тем не менее, важно понимать, какую именно защиту они обеспечивают и где находится граница их возможностей.
Шаблоны Django экранируют специальные символы, которые обычно создают проблемы для HTML. И хотя экранирование защищает пользователя от большинства видов вредоносного ввода, оно не является панацеей. Например, оно не защитит от такого:
<style class={{ var }}>...</style>
Если var содержит 'class1 onmouseover=javascript:func()', то это может вылиться в неавторизованный запуск JavaScript, здесь всё зависит от того, как браузер интерпретирует несовершенный HTML. (Установка кавычек вокруг значения атрибута решает данную проблему.)
Важно обратить особое внимание на использование is_safe совместно с сторонними шаблонными тегами, с шаблонным тегом safe, с mark_safe и когда автоматическое экранирование отключено.
Дополнительно, если вы используйте шаблонную систему для вывода контента, отличного от HTML, то там могут быть отдельные символы и слова, которые требуют экранирования.
Вы также должны быть очень осторожны при сохранении HTML в базе данных, особенно в случае, когда этот HTML будет отображаться впоследствии.
Защита от подделки межсайтового запроса (CSRF)¶
CSRF атаки позволяют недобросовестному пользователю выполнять действия от имени другого пользователя, без ведома последнего или его согласия.
Django обладает встроенной защитой против большинства типов CSRF атак, если вы активировали и использовали её там, где это необходимо. Однако, как это обычно бывает, существуют ограничения. Например, есть возможность отключить защиту CSRF глобально или на уровне отдельного представления. Такое можно делать, только если вы точно уверены в своих действиях. Существуют другие ограничения, если у вашего сайта есть поддомены, не находящиеся под вашим управлением.
CSRF защита работает, проверяя секретную метку в каждом POST запросе. Она не позволяет злоумышленнику просто сформировать POST запрос формы к вашему сайту и дать возможность другому авторизованному пользователю нечаянно отправить эту форму. Злоумышленнику потребуется знать содержимое секретной метки, которое зависит от пользователя (используются куки).
При работе через HTTPS, CsrfViewMiddleware будет проверять, что заголовок HTTP Referer установлен на URL того же источника (включая поддомен и порт). Так как HTTPS предоставляет дополнительную защиту, надо всегда проверять, что соединения используют его всегда, перенаправляя на HTTPS запросы по незащищённым соединениям и используя HSTS для браузеров, которые это поддерживают.
Будьте очень внимательны, декорируя представления с помощью csrf_exempt, когда в этом нет явной необходимости.
Защита от внедрения SQL¶
Внедрение SQL — это тип атаки, когда недобросовестный пользователь имеет возможность выполнить в базе данных определённый SQL запрос. Результатом выполнения такого запроса может быть удаление или даже утечка данных.
Забросы через Django ORM защищены от SQL-инъекции т.к. они формируются с использованием параметров запроса. SQL код запроса отделен от параметров запроса. Т.к. параметры запроса могут поступать от пользователя и быть не безопасными, они экранируют на уровне драйвера базы данных.
Django предоставляет разработчикам возможность писать запросы напрямую или выполнять собственные запросы. Эти возможности следует использовать умеренно и всегда обращать пристальное внимание на экранирование всех параметров, которые предоставлены пользователем. Также следует проявлять осторожность при использовании extra() и RawSQL.
Защита от скликивания¶
Скликивание — это атака, при которой вредоносный сайт подменяет другой сайт используя <iframe>. В результате этой атаки ничего не подозревающий пользователь принуждается к выполнению определённых действий на целевом сайте.
Django предоставляет защиту от этой атаки в виде модуля X-Frame-Options, который, при использовании соответствующего браузера, может предотвратить отображение сайта внутри фрейма. Есть возможность отключить данную защиту для выбранных представлений или настроить значение отправляемого заголовка.
Этот функциональный слой настоятельно рекомендуется использовать на любом сайте, страницы которого не должны отображаться внутри другого сайта. Можно позволить такое отображение для простых страниц.
SSL/HTTPS¶
Лучше предоставлять доступ к вашему сайту только через HTTPS. При отсутствии HTTPS злоумышленник имеет возможность перехватывать аутентификационные данные или любую другую информацию, передаваемую между клиентом и сервером. А в случае активной атаки — может даже изменять данные, передаваемые в любом направлении.
Если вам нужна защита, предоставляемая HTTPS, и на сервере произведена соответствующая настройка ПО, то надо выполнить ещё несколько шагов, чтобы быть уверенным в защите своей информации:
При необходимости, установите параметр конфигурации
SECURE_PROXY_SSL_HEADER, чтобы показать, что вы поняли все предупреждения. Отказ от этого может привести к CSRF проблемам, а отказ сделать это правильно также может быть опасен!Настройте перенаправление HTTP запросов на HTTPS, указав
TrueвSECURE_SSL_REDIRECT.Обратите внимание на предостережения в разделе
SECURE_PROXY_SSL_HEADER. В случае обратного прокси-сервера может быть проще и безопаснее настроить основной веб-сервер на перенаправление на HTTPS.Использование „безопасных“ куки.
Если браузер изначально подключается через HTTP, что характерно для большинства браузеров, есть возможность утечки существующих кук. По этой причине вам сделать установить параметры
SESSION_COOKIE_SECUREиCSRF_COOKIE_SECUREвTrue. Это заставить браузер отправлять такие куки только через HTTPS. Следует отметить, это сделает невозможным работу сессий через HTTP, а CSRF защита не будет принимать POST данные, полученные через HTTP (это решается с помощью перенаправления HTTP трафика через HTTPS).Использование HTTP Strict Transport Security (HSTS)
HSTS — это HTTP-заголовок, который сообщает браузеру, что все будущие подключения к определенному сайту всегда должны использовать HTTPS. В сочетании с перенаправлением запросов через HTTP на HTTPS это гарантирует, что соединения всегда будут пользоваться дополнительной безопасностью SSL при условии, что произошло одно успешное соединение. HSTS можно настроить с помощью
SECURE_HSTS_SECONDS,SECURE_HSTS_INCLUDE_SUBDOMAINSиSECURE_HSTS_PRELOADили на веб-сервере.
Проверка заголовка хоста¶
Django использует заголовок Host, предоставляемый клиентом, для создания URL в определённых случаях. Несмотря на то, что эти данные безопасны с точки зрения Cross Site Scripting атак, поддельный заголовок Host может быть использован для атак CSRF, подмены кэша и для подмены ссылок в сообщениях электронной почты.
Поскольку даже по-видимому безопасные конфигурации веб-сервера восприимчивы к поддельным заголовкам Host заголовки, Django проверяет этот заголовок относительно параметра конфигурации ALLOWED_HOSTS с помощью метода django.http.HttpRequest.get_host().
Эта проверка применяется только через get_host(). Если ваш код получает содержимое заголовка Host напрямую из request.META, то вы игнорируете эту защиту.
Для подробностей смотрите полную документацию на параметр конфигурации ALLOWED_HOSTS.
Предупреждение
Предыдущие версии этого документа рекомендовали настраивать ваш веб сервер на проверку входящих HTTP заголовков Host. Рекомендация всё ещё в силе, на многих веб-серверах используется конфигурация, которая не проверяет заголовок Host, хотя по всем признакам должна это делать. Например, даже если Apache настроен таким образом, что ваш сайт работает на нестандартном виртуальном узле с установленным ServerName, всё ещё есть возможность предоставить поддельный заголовок для этого узла. Таким образом, Django теперь требует явного определения параметра конфигурации ALLOWED_HOSTS, не доверяя конфигурации самого веб сервера.
Дополнительно Django требует явную активацию поддержки заголовка X-Forwarded-Host (через параметр конфигурации USE_X_FORWARDED_HOST), если ваша конфигурация в нём нуждается.
Политика Referrer¶
Браузеры используют заголовок Referer для передачи информации сайту о том, как пользователь попал на него. Устанавливая Политику Referrer вы можете помочь защитить приватность ваших пользователей, указывая при каких обстоятельствах устанавливается заголовок Referer. Обратитесь к соответствующему разделу настроек безовасности для подробностей.
Политика открытия перекрестного происхождения¶
Заголовок политики открытия перекрестного происхождения (COOP) позволяет браузерам изолировать окно верхнего уровня от других документов, помещая их в другую контекстную группу, чтобы они не могли напрямую взаимодействовать с окном верхнего уровня. Если документ, защищенный COOP, открывает всплывающее окно из разных источников, свойство всплывающего окна window.opener будет иметь значение null. COOP защищает от атак из разных источников. Дополнительную информацию см. в разделе политики открытия перекрестного происхождения в справочнике по промежуточному программному обеспечению безопасности <cross-origin-opener-policy>`.
Безопасность сессии¶
Аналогично требованиям ограничений CSRF, чтобы сайт был настроен так, чтобы недоверенные пользователи не имели доступа ни к одному поддомену, django.contrib.sessions также имеет ограничения. Обратитесь к разделу по безопасной настройке сессий для подробностей.
Контент, загружаемый пользователями¶
Примечание
Обратите внимание на раздачу файлов из облачного сервиса или CDN для избежания некоторых из этих проблем.
Если ваш сайт поддерживает загрузку файлов, настоятельно рекомендуется ограничить эту загрузку в конфигурации вашего веб-сервера разумным размером, чтобы предотвратить атаки типа «отказ в обслуживании» (DOS). В Apache это можно легко настроить с помощью директивы LimitRequestBody.
Если вы самостоятельно раздаете статические файлы, убедитесь, что обработчики, как
mod_phpв Apache, который будет выполнять статические файлы в виде кода, будут отключены. Вы же не хотите, чтобы пользователи могли выполнить произвольный код путем загрузки и запроса специально созданного файла.Обработка загрузки медиа файлов в Django имеет некоторые уязвимости, если медиа файлы раздаются без учета некоторых правил безопасности. В частности, HTML файл может быть загружен в виде изображения, если этот файл содержит правильный заголовок PNG с последующим вредоносным HTML. Этот файл будет проходить проверку библиотеками, которые Django использует для обработки изображений (Pillow) в
ImageField. Когда этот файл впоследствии отображается для пользователя, он может отображаться как HTML в зависимости от типа и конфигурации веб-сервера.Не существует идеального технического решения на уровне Django для безопасной проверки всех типов файлов, которые могут загрузить другие пользователи. Однако, можно предпринять некоторые другие способы, чтобы обезопасить себя от атаки:
Один класс атак можно предотвратить путем раздачи медиа файлов с отдельного домена верхнего уровня или второго уровня. Это предотвращает любые эксплойты, которые могут быть заблокированы same-origin policy, таких как межсайтовый скриптинг. Например, если ваш сайт работает на
example.com, вам следует раздавать медиа файлы (настройкаMEDIA_URL) с другого домена, напримерusercontent-example.com. Но не достаточно раздавать медиа файлы с поддомен видаusercontent.example.com.Помимо этого, приложения могут определить список допустимых расширений файлов для загружаемых пользователем файлов и настроить веб-сервер для обслуживания только таких файлов.
Дополнительные вопросы безопасности¶
Несмотря на то, что Django обеспечивает хорошую защиту безопасности «из коробки», по-прежнему важно правильно развернуть ваше приложение и воспользоваться преимуществами защиты веб-сервера, операционной системы и других компонентов.
Убедитесь, что ваш код Python находится за пределами корня веб-сервера. Это гарантирует, что ваш код Python не будет случайно использован в виде обычного текста (или случайно выполнен).
Будьте осторожны с любыми файлами, которые загружены пользователями.
Django не ограничивает запросы на аутентификацию пользователей. Чтобы защититься от атак грубой силы на систему аутентификации, вы можете рассмотреть возможность развертывания плагина Django или модуля веб-сервера для регулирования этих запросов.
Держите
SECRET_KEYиSECRET_KEY_FALLBACKS, если они используются, в секрете.Хорошей идеей будет ограничить доступ к вашей системе кэширования и к базе данных с помощью фаервола.
Обратите внимание на список Топ 10 уязвимостей на сайте Open Web Application Security Project (OWASP). Хотя Django содержит инструменты для защиты от некоторых из них, остальные должны быть учтены в архитектуре вашего проекта.
Mozilla обсуждает различные темы, касающиеся «веб-безопасности». На их страницах также описаны принципы безопасности, применимые к любой системе.