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

Веб-приложения обычно сталкиваются со всевозможными проблемами безопасности, и очень трудно сделать все правильно. Flask пытается решить некоторые из этих проблем за вас, но есть еще несколько, о которых вы должны позаботиться сами.

Межсайтовый скриптинг (XSS)

Межсайтовый скриптинг - это концепция внедрения произвольного HTML (а вместе с ним и JavaScript) в контекст веб-сайта. Чтобы устранить эту проблему, разработчики должны правильно экранировать текст, чтобы он не мог включать произвольные HTML-теги. Более подробную информацию об этом можно найти в статье Википедии Cross-Site Scripting.

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). Если злоумышленник теперь создаст страницу, которая отправляет пост-запрос на эту страницу с некоторым JavaScript, ему достаточно обмануть некоторых пользователей, чтобы загрузить эту страницу, и их профили будут удалены.

Представьте, что вы управляете Facebook с миллионами одновременных пользователей, и кто-то рассылает ссылки на изображения маленьких котят. Когда пользователи перейдут на эту страницу, их профили будут удалены, пока они будут смотреть на изображения пушистых кошек.

Как вы можете предотвратить это? В принципе, для каждого запроса, изменяющего содержимое на сервере, вам придется либо использовать одноразовый токен и хранить его в cookie также передавать его вместе с данными формы. После повторного получения данных на сервере вы должны будете сравнить два маркера и убедиться, что они равны.

Почему Flask не делает этого за вас? Идеальным местом для этого является фреймворк валидации форм, которого во Flask нет.

Безопасность JSON

В версии Flask 0.10 и ниже jsonify() не сериализовывал массивы верхнего уровня в JSON. Это было связано с уязвимостью безопасности в ECMAScript 4.

ECMAScript 5 закрыл эту уязвимость, поэтому уязвимыми остаются только очень старые браузеры. Все эти браузеры имеют other more serious vulnerabilities, поэтому это поведение было изменено, и jsonify() теперь поддерживает сериализацию массивов.

Заголовки безопасности

Браузеры распознают различные заголовки ответа для контроля безопасности. Мы рекомендуем ознакомиться с каждым из приведенных ниже заголовков для использования в вашем приложении. Для управления HTTPS и заголовками безопасности можно использовать расширение Flask-Talisman.

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

response.headers['X-Frame-Options'] = 'SAMEORIGIN'

HTTP Public Key Pinning (HPKP)

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

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

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

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

Скрытые символы, такие как символ обратного пробела (\b, ^H), могут привести к тому, что текст будет отображаться в HTML не так, как он интерпретируется, если pasted into a terminal.

Например, import y\bose\bm\bi\bt\be\b отображается как import yosemite в HTML, но при вставке в терминал применяются обратные пробелы, и он становится import os.

Если вы ожидаете, что пользователи будут копировать и вставлять недоверенный код с вашего сайта, например, из комментариев, размещенных пользователями в техническом блоге, рассмотрите возможность применения дополнительной фильтрации, например, замены всех символов \b.

body = body.replace("\b", "")

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

Вернуться на верх