Spec-Zone.ru › Flask 2.0

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

Веб-приложения обычно сталкиваются со множеством проблем безопасности, и очень сложно все сделать правильно. 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'
  • 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. Это предотвращает класс атак, где щелчки в внешней рамке могут быть невидимо переведены в щелчки по элементам вашей страницы. Это также известно как «clickjacking».

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

X-XSS-Protection

Браузер попытается предотвратить отражённые атаки XSS, не загружая страницу, если запрос содержит что-то, что выглядит как JavaScript, а ответ содержит те же данные.

response.headers['X-XSS-Protection'] = '1; mode=block'
  • https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-XSS-Protection

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

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

  • Secure ограничивает cookie только HTTPS-трафиком.
  • HttpOnly защищает содержимое cookie от чтения с помощью JavaScript.
  • SameSite ограничивает способ отправки cookie с запросами со сторонних сайтов. Может быть установлен на 'Lax' (рекомендуется) или 'Strict'. Lax предотвращает отправку cookie с подверженными CSRF запросами со сторонних сайтов, таких как отправка формы. Strict предотвращает отправку cookie со всеми внешними запросами, включая переход по обычным ссылкам.
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 после указанного времени или текущего времени плюс указанный срок, соответственно. Если ни один параметр не установлен, cookie будет удалён при закрытии браузера.

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

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

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 для подписи и проверки других значений cookie (или любых значений, которые требуют безопасных подписей).

  • 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", "")

Большинство современных терминалов будут предупреждать о скрытых символах при вставке и удалять их, поэтому это не строго необходимо. Также можно создавать опасные команды другими способами, которые нельзя отфильтровать. В зависимости от использования вашего сайта, может быть полезно отображать предупреждение о копировании кода в целом.

© 2007–2021 Pallets
Licensed under the BSD 3-clause License.
https://flask.palletsprojects.com/en/2.0.x/security/

Spec-Zone.ru

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