Spec-Zone.ru › Flask

Соображения по безопасности

Веб-приложения подвержены множеству потенциальных проблем с безопасностью, и сложно добиться идеальной безопасности или даже понять, что значит «идеальная» безопасность в целом. Flask пытается решить некоторые из этих проблем по умолчанию, но есть и другие аспекты, о которых вам нужно позаботиться самостоятельно. Многие из этих решений представляют собой компромиссы и зависят от конкретных потребностей и модели угроз каждого приложения. Многие хостинговые платформы могут обрабатывать определенные типы проблем без необходимости обработки их Flask-приложением.

Использование ресурсов

Распространенной категорией атак является «Отказ в обслуживании» (DoS или DDoS). Это очень обширная категория, и различные варианты нацелены на разные уровни развернутого приложения. В общем, что-то делается для увеличения времени обработки или использования памяти для обработки каждого запроса до такой степени, что ресурсов становится недостаточно для обработки законных запросов.

Flask предоставляет несколько параметров конфигурации для обработки использования ресурсов. Их также можно задавать для отдельных запросов, чтобы настроить только этот запрос. Документация по каждому из них содержит более подробные сведения.

  • MAX_CONTENT_LENGTH или Request.max_content_length управляет объёмом данных, которые будут считываться из запроса. По умолчанию он не установлен, хотя он всё равно будет блокировать действительно неограниченные потоки, если WSGI-сервер не указывает поддержку.
  • MAX_FORM_MEMORY_SIZE или Request.max_form_memory_size управляет размером любого не-файлового multipart/form-data поля. По умолчанию он установлен в 500 КБ.
  • MAX_FORM_PARTS или Request.max_form_parts управляет количеством multipart/form-data полей, которые могут быть обработаны. По умолчанию он установлен в 1000. В сочетании с настройками max_form_memory_size, это означает, что форма будет занимать не более 500 МБ памяти.

Независимо от этих настроек, следует также проверить доступные параметры от вашей операционной системы, развертывания в контейнере (Docker и т. д.), WSGI-сервера, HTTP-сервера и хостинговой платформы. Они, как правило, предоставляют способы установки лимитов ресурсов процесса, таймаутов и других проверок независимо от того, как настроена 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, предотвращая атаки «человек посередине» (MITM).

response.headers['Strict-Transport-Security'] = 'max-age=31536000; includeSubDomains'
  • https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security

Политика безопасности контента (CSP)

Указывает браузеру, откуда он может загружать различные типы ресурсов. Этот заголовок следует использовать по возможности, но для определения правильной политики для вашего сайта требуется работа. Очень строгая политика будет:

response.headers['Content-Security-Policy'] = "default-src 'self'"
  • https://csp.withgoogle.com/docs/index.html
  • https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy

X-Content-Type-Options

Принуждает браузер соблюдать тип содержимого ответа вместо попытки его определения, что может быть использовано для создания атаки межсайтового скриптинга (XSS).

response.headers['X-Content-Type-Options'] = 'nosniff'
  • https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Content-Type-Options

X-Frame-Options

Препятствует внешним сайтам от встраивания вашего сайта в iframe. Это предотвращает класс атак, где щелчки во внешней рамке могут быть невидимо переведены в щелчки по элементам вашей страницы. Это также известно как «кликджекинг».

response.headers['X-Frame-Options'] = 'SAMEORIGIN'
  • https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options

Параметры Set-Cookie

Эти параметры могут быть добавлены к заголовку Set-Cookie для повышения их безопасности. Flask имеет параметры конфигурации для установки этих параметров на куки сеанса. Они могут быть установлены и на другие куки.

  • Secure ограничивает куки только трафиком HTTPS.
  • HttpOnly защищает содержимое куки от чтения с помощью JavaScript.
  • SameSite ограничивает отправку куки с запросами с внешних сайтов. Может быть установлено в 'Lax' (рекомендуется) или 'Strict'. Lax предотвращает отправку куки с подверженными CSRF-атакам запросами с внешних сайтов, например, при отправке формы. Strict предотвращает отправку куки со всеми внешними запросами, включая переходы по обычным ссылкам.
app.config.update(
    SESSION_COOKIE_SECURE=True,
    SESSION_COOKIE_HTTPONLY=True,
    SESSION_COOKIE_SAMESITE='Lax',
)

response.set_cookie('username', 'flask', secure=True, httponly=True, samesite='Lax')

Указание Expires или Max-Age параметров удалит куки после заданного времени или текущего времени плюс срок действия соответственно. Если ни один параметр не установлен, куки будет удален при закрытии браузера.

# cookie expires after 10 minutes
response.set_cookie('snakes', '3', max_age=600)

Для куки сеанса, если session.permanent установлен, тогда PERMANENT_SESSION_LIFETIME используется для установки срока действия. Встроенная функция куки Flask проверяет, что криптографическая подпись не старше этого значения. Уменьшение этого значения может помочь смягчить атаки с повторным использованием, где перехваченные куки могут быть отправлены позже.

app.config.update(
    PERMANENT_SESSION_LIFETIME=600
)

@app.route('/login', methods=['POST'])
def login():
    ...
    session.clear()
    session['user_id'] = user.id
    session.permanent = True
    ...

Используйте itsdangerous.TimedSerializer для подписи и проверки других значений куки (или любых значений, требующих безопасных подписей).

  • https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies
  • https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie

HTTP Public Key Pinning (HPKP)

Это сообщает браузеру об аутентификации с сервером только с помощью определенного ключа сертификата, чтобы предотвратить атаки MITM.

Предупреждение

Будьте осторожны при включении этого параметра, так как его очень сложно отменить, если вы неправильно настроили или обновили свой ключ.

  • https://developer.mozilla.org/en-US/docs/Web/HTTP/Public_Key_Pinning

Копирование/вставка в терминал

Скрытые символы, такие как символ удаления (\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/stable/web-security/

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API