Spec-Zone.ru › Flask 1.1

Меры Безопасности

Веб-приложения обычно сталкиваются со всевозможными проблемами безопасности, и очень сложно все сделать правильно. 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 не защищает. Атрибут тега a href может содержать URI javascript:, который браузер выполнит при нажатии, если он не защищён должным образом.

<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)

Это сообщает браузеру аутентифицироваться на сервере, используя только определённый ключ сертификата, чтобы предотвратить атаки «человек посередине».

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

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

  • 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–2020 Pallets
Licensed under the BSD 3-clause License.
https://flask.palletsprojects.com/en/1.1.x/security/

Spec-Zone.ru

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