Безопасность
Веб-приложения обычно сталкиваются с различными проблемами безопасности, и очень сложно сделать все правильно. Flask пытается решить некоторые из этих проблем за вас, но есть несколько дополнительных, о которых вам нужно позаботиться самостоятельно.
Межсайтовый скриптинг (XSS)
Межсайтовый скриптинг — это концепция внедрения произвольного HTML (и вместе с ним JavaScript) в контекст веб-сайта. Для устранения этой проблемы разработчики должны правильно экранировать текст, чтобы он не содержал произвольных HTML-тегов. Для получения дополнительной информации ознакомьтесь со статьей Википедии о Межсайтовом скриптинге.
Flask настраивает Jinja2 на автоматическое экранирование всех значений, если явно не указано обратное. Это должно исключить все проблемы XSS, возникающие в шаблонах, но есть еще места, где нужно быть осторожным:
- формирование HTML без помощи Jinja2
- вызов
Markupдля данных, отправленных пользователем - отправка HTML из загруженных файлов, никогда этого не делайте, используйте заголовок
Content-Disposition: attachmentдля предотвращения этой проблемы. - отправка текстовых файлов из загруженных файлов. Некоторые браузеры используют угадывание типа контента на основе первых нескольких байтов, поэтому пользователи могут обмануть браузер для выполнения HTML.
Еще одна очень важная вещь — это атрибуты без кавычек. Хотя Jinja2 может защитить вас от проблем XSS, экранируя HTML, есть одна вещь, от которой он не может вас защитить: XSS путем внедрения атрибутов. Чтобы противостоять этому возможному вектору атаки, обязательно используйте двойные или одинарные кавычки для своих атрибутов при использовании выражений Jinja в них:
<input value="{{ value }}">
Почему это необходимо? Потому что, если вы этого не сделаете, злоумышленник может легко внедрить пользовательские обработчики JavaScript. Например, злоумышленник может внедрить такой фрагмент HTML+JavaScript:
onmouseover=alert(document.cookie)
Когда пользователь затем наведёт курсор мыши на поле ввода, куки будут представлены пользователю в окне предупреждения. Но вместо того, чтобы показать куки пользователю, опытный злоумышленник может также выполнить любой другой код JavaScript. В сочетании с инъекциями CSS злоумышленник может даже заставить элемент заполнить всю страницу, так что пользователю достаточно навести курсор мыши на любую область страницы, чтобы вызвать атаку.
Существует один класс проблем XSS, от которых экранирование Jinja не защищает. Атрибут href тега a может содержать URI javascript:, который браузер выполнит при нажатии, если он не защищен должным образом.
<a href="{{ value }}">click here</a>
<a href="javascript:alert('unsafe');">click here</a>
Для предотвращения этого вам необходимо установить заголовок ответа Политика безопасности контента (CSP).
Межсайтовая подделка запроса (CSRF)
Еще одна серьезная проблема — CSRF. Это очень сложная тема, и я не буду подробно её описывать здесь, просто упомяну, что это такое и как теоретически от неё защититься.
Если ваша информация об аутентификации хранится в куках, у вас есть неявное управление состоянием. Состояние «авторизован» контролируется куки, и эта куки отправляется с каждым запросом на страницу. К сожалению, это включает запросы, инициированные сторонними сайтами. Если вы об этом не позаботитесь, некоторые люди могут обмануть пользователей вашего приложения с помощью социальной инженерии, чтобы те совершили нежелательные действия, не зная об этом.
Предположим, у вас есть определённый URL, который, при отправке POST запросов, удаляет профиль пользователя (скажем, http://example.com/user/delete). Если теперь злоумышленник создаёт страницу, которая отправляет POST-запрос на эту страницу с помощью JavaScript, ему нужно только обмануть некоторых пользователей, чтобы они загрузили эту страницу, и их профили будут удалены.
Представьте, что вы запускаете Facebook с миллионами одновременных пользователей, и кто-то отправляет ссылки на изображения маленьких котят. Когда пользователи перейдут по этой ссылке, их профили будут удалены, пока они смотрят изображения пушистых котиков.
Как вы можете предотвратить это? В основном для каждого запроса, изменяющего содержимое на сервере, вам нужно использовать одноразовый токен и сохранить его в куки **и** также передать его с данными формы. После получения данных на сервере снова, вам необходимо сравнить два токена и убедиться, что они равны.
Почему Flask не делает этого за вас? Идеальное место для этого — фреймворк проверки форм, которого в Flask нет.
Безопасность JSON
В Flask 0.10 и ниже jsonify() не сериализовывал массивы верхнего уровня в JSON. Это было из-за уязвимости безопасности в ECMAScript 4.
ECMAScript 5 закрыл эту уязвимость, поэтому уязвимыми остаются только очень старые браузеры. У всех этих браузеров есть и другие более серьезные уязвимости, поэтому это поведение было изменено и jsonify() теперь поддерживает сериализацию массивов.
Заголовки безопасности
Браузеры распознают различные заголовки ответа для управления безопасностью. Мы рекомендуем ознакомиться с каждым из заголовков ниже для использования в вашем приложении. Расширение Flask-Talisman можно использовать для управления HTTPS и заголовками безопасности за вас.
HTTP Strict Transport Security (HSTS)
Сообщает браузеру преобразовать все HTTP-запросы в HTTPS, предотвращая атаки типа «man-in-the-middle» (MITM).
response.headers['Strict-Transport-Security'] = 'max-age=31536000; includeSubDomains'
Политика безопасности контента (CSP)
Указывает браузеру, откуда он может загружать различные типы ресурсов. Этот заголовок следует использовать по возможности, но для определения правильной политики для вашего сайта требуется определённая работа. Очень строгая политика будет:
response.headers['Content-Security-Policy'] = "default-src 'self'"
X-Content-Type-Options
Принуждает браузер соблюдать тип контента ответа вместо попытки его определить, что может быть использовано для генерации атаки межсайтового скриптинга (XSS).
response.headers['X-Content-Type-Options'] = 'nosniff'
X-Frame-Options
Препятствует сторонним сайтам от встраивания вашего сайта в iframe. Это предотвращает класс атак, где клики во внешнем фрейме могут быть невидимо переведены в клики по элементам вашей страницы. Это также известно как «кликджекинг».
response.headers['X-Frame-Options'] = 'SAMEORIGIN'
HTTP Public Key Pinning (HPKP)
Это сообщает браузеру аутентифицироваться на сервере только с использованием определенного ключа сертификата, чтобы предотвратить атаки типа MITM.
Предупреждение
Будьте осторожны при включении этого, так как его очень сложно отменить, если вы неправильно настроите или обновите свой ключ.
Копирование/вставка в терминал
Скрытые символы, такие как символ удаления (\b, ^H) могут привести к тому, что текст будет отображаться в HTML по-другому, чем при вставке в терминал.
Например, import y\bose\bm\bi\bt\be\b отображается как import yosemite в HTML, но при вставке в терминал удаления применяются, и текст становится import os.
Если вы ожидаете, что пользователи будут копировать и вставлять небезопасный код с вашего сайта, например, из комментариев пользователей на техническом блоге, рассмотрите применение дополнительной фильтрации, например, замену всех \b символов.
body = body.replace("\b", "")
Большинство современных терминалов предупреждают о скрытых символах и удаляют их при вставке, поэтому это не строго необходимо. Также можно создавать опасные команды другими способами, которые невозможно отфильтровать. В зависимости от использования вашего сайта, может быть полезно отображать предупреждение о копировании кода в целом.
© 2007–2022 Pallets
Licensed under the BSD 3-clause License.
https://flask.palletsprojects.com/en/2.2.x/security/