Учет мер безопасности
Веб-приложения обычно сталкиваются со множеством проблем безопасности, и очень сложно все сделать правильно. 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)
Когда пользователь затем перемещает курсор над полем ввода, cookie будет представлен пользователю в окне сообщения. Но вместо того, чтобы показывать cookie пользователю, хитрый злоумышленник может также выполнить любой другой код JavaScript. В сочетании с инъекциями CSS злоумышленник может даже заставить элемент заполнить всю страницу, так что пользователю нужно будет только навести курсор мыши на любую часть страницы, чтобы активировать атаку.
Существует один класс проблем XSS, от которых экранирование Jinja не защищает. Атрибут href тега a может содержать javascript: URI, который браузер выполнит при нажатии, если он не защищен должным образом.
<a href="{{ value }}">click here</a>
<a href="javascript:alert('unsafe');">click here</a>
Чтобы предотвратить это, вам нужно будет установить заголовок ответа Политика безопасности содержимого (CSP).
Межсайтовая подделка запроса (CSRF)
Еще одна большая проблема — CSRF. Это очень сложная тема, и я не буду подробно ее описывать здесь, а лишь упомяну, что это такое и как теоретически предотвратить ее.
Если ваша информация об аутентификации хранится в cookie, у вас есть неявное управление состоянием. Состояние «авторизован» контролируется cookie, и этот cookie отправляется с каждым запросом на страницу. К сожалению, это включает в себя запросы, инициированные сторонними сайтами. Если вы не учитываете это, некоторые люди могут обмануть пользователей вашего приложения с помощью социальной инженерии, чтобы выполнить вредные действия, не зная об этом.
Допустим, у вас есть конкретный URL, который при отправке POST запросов удалит профиль пользователя (например, http://example.com/user/delete). Если теперь злоумышленник создаст страницу, которая отправляет POST-запрос на эту страницу с помощью JavaScript, то ему нужно только обмануть некоторых пользователей, чтобы они загрузили эту страницу, и их профили будут удалены.
Представьте, что вы управляете Facebook с миллионами одновременных пользователей, и кто-то отправляет ссылки на изображения милых котят. Когда пользователи перейдут по этой ссылке, их профили будут удалены, пока они смотрят на изображения пушистых котов.
Как вы можете предотвратить это? В основном для каждого запроса, изменяющего содержимое на сервере, вам необходимо использовать одноразовый токен и хранить его в cookie и также передавать его в данных формы. После получения данных на сервер снова необходимо сравнить два токена и убедиться, что они равны.
Почему Flask не делает этого за вас? Идеальное место для этого — система проверки форм, которой нет в Flask.
Безопасность JSON
В Flask 0.10 и ниже jsonify() не сериализовали массивы верхнего уровня в JSON. Это было связано с уязвимостью в ECMAScript 4.
ECMAScript 5 закрыл эту уязвимость, поэтому уязвимы только очень старые браузеры. Все эти браузеры имеют другие более серьезные уязвимости, поэтому это поведение было изменено, и jsonify() теперь поддерживает сериализацию массивов.
Заголовки безопасности
Браузеры распознают различные заголовки ответа для управления безопасностью. Мы рекомендуем рассмотреть каждый из заголовков ниже для использования в вашем приложении. Расширение Flask-Talisman можно использовать для управления HTTPS и заголовков безопасности за вас.
HTTP Strict Transport Security (HSTS)
Указывает браузеру преобразовывать все HTTP-запросы в HTTPS, предотвращая атаки «человек посередине» (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", "")
Большинство современных терминалов будут предупреждать и удалять скрытые символы при вставке, поэтому это не строго обязательно. Также можно создавать опасные команды другими способами, которые невозможно отфильтровать. В зависимости от использования вашего сайта, может быть полезно отображать предупреждение о копировании кода в целом.
© 2010 Pallets
Licensed under the BSD 3-clause License.
https://flask.palletsprojects.com/en/3.0.x/security/