В статье ниже я покажу, какие именно дыры в безопасности сайтов скрываются за разными уровнями критичности. Посмотрим, какие уязвимости сканер находил особенно часто, почему они могут возникать и как защититься.
Все уязвимости веб-приложений Qualys делит на три уровня критичности: низкий, средний и высокий. Если смотреть на распределение по «тяжести», кажется, что все не так плохо. Уязвимостей с высоким уровнем критичности мало, в основном все некритичные:
Но некритичные – не значит безобидные. Они тоже могут нанести серьезный ущерб.
Топ «некритичных» уязвимостей
- Уязвимости, связанные со смешанным содержимым.
Стандартом безопасности сайтов считается передача данных между клиентом и сервером по протоколу HTTPS, который поддерживает шифрование и защищает информацию от перехвата.
Некоторые сайты используют смешанное содержимое: передают часть данных через незащищенный протокол HTTP. Чаще так передают пассивное содержимое – информацию, которая влияет только на отображение сайта: картинки, css-стили. Но иногда так передается и активное содержимое: скрипты, которые управляют поведением сайта. В этом случае при помощи специального ПО можно анализировать приходящую от сервера информацию с активным содержимым, модифицировать на лету свои ответы и заставлять машину работать так, как не было задумано ее создателями.
Браузеры новых версий предупреждают пользователей, что сайты со смешанным содержимым небезопасны, и блокируют контент. Разработчики сайтов также получают предупреждения от браузера в консоли. Например, так это выглядит в Firefox:
Чем опасно: Злоумышленники используют незащищенный протокол для перехвата информации о пользователе, подмены скриптов и отправки запросов на сайт от его имени. Даже если посетитель сайта не вводил данных, это не защищает его от фишинга – выуживания конфиденциальной информации мошенническими методами. Например, с помощью скрипта можно перенаправить пользователя на небезопасный сайт, который маскируется под знакомый пользователю. В отдельных случаях злонамеренный сайт выглядит даже лучше оригинала, и пользователь может сам заполнить форму и передать конфиденциальные данные.
Что стоит помнить веб-разработчику: Даже если администратор сайта установил и настроил SSL/TLS-сертификат, уязвимость может возникнуть из-за человеческого фактора. Например, если на какой-то из страниц поставили не относительную ссылку, а абсолютную с http, и вдобавок не настроили редиректы с http на https.
Обнаружить смешанный контент на сайте можно с помощью браузера: поискать по исходному коду страницы, почитать уведомления в консоли разработчика. Однако разработчику предстоит долго и нудно ковыряться в коде. Ускорить процесс можно с автоматизированными средствами анализа, например: SSL Check, свободное ПО Lighthouse или платный софт Screaming Frog SEO Spider.
Также уязвимость может возникнуть из-за проблем с legacy-code – кодом, который достался в наследство. К примеру, если часть страниц генерируется по старому шаблону, где не учитывается переход сайтов на https.
- Куки без флагов «HTTPOnly» и «secure».
Атрибут «HTTPOnly» защищает файлы куки от обработки скриптами, которые злоумышленники используют для кражи пользовательских данных. Флаг «secure» не разрешает передачу куки в открытом виде. Обмен данными будет разрешен, только если для отправки куки используется защищенный протокол HTTPS.
Оба атрибута прописываются в свойствах куки:
Set-Cookie: Secure; HttpOnly
Чем опасно: Если разработчик сайта не указал эти атрибуты, злоумышленник может перехватить информацию пользователя из куки и воспользоваться ей. Если куки используются для аутентификации и авторизации, он сможет угнать сессию пользователя и совершить действия на сайте от его имени.
Что стоит помнить веб-разработчику: Как правило, в популярных фреймворках эти атрибуты задаются автоматически. Но все равно проверьте конфигурацию веб-сервера и поставьте флаг: Set-Cookie HttpOnly; Secure.
При этом атрибут «HTTPOnly» сделает куки невидимыми и для вашего собственного JavaScript.
- Path-Based Vulnerabilities («путевые» уязвимости).
Сканер сообщает о такой уязвимости, если находит публично доступный файл или директорию сайта с потенциально конфиденциальной информацией. Например, обнаруживает отдельные файлы с конфигурацией системы или доступ к файловой системе целиком. Такая ситуация возможна, если на сайте неправильно заданы права доступа.
Чем опасно: Если файловая система «торчит наружу», злоумышленник может провалиться в интерфейс операционной системы и попробовать найти папки с паролями, если они хранятся в открытом виде (не надо так!). Или можно украсть хэши паролей и перебором подобрать пароль, а также попытаться поднять привилегии в системе и продвигаться вглубь инфраструктуры.
Что стоит помнить веб-разработчику: Не забывайте про права доступа и конфигурируйте платформу, веб-сервер, веб-приложение, чтобы нельзя было «сбежать» из веб-директории.
- Формы для ввода конфиденциальных данных с включенной функцией автозаполнения.
Если пользователь часто заполняет формы на сайтах, его браузер сохраняет эту информацию с помощью функции автозаполнения.
Формы на сайтах могут включать поля с конфиденциальной информацией, например, пароли или номера кредитных карт. Для таких полей стоит на самом сайте отключить функцию автозаполнения форм.
Чем опасно: Если браузер пользователя сохранит конфиденциальную информацию, злоумышленник может перехватить ее позже, например, с помощью фишинга. По сути, веб-разработчик, забывший об этом нюансе, подставляет своих пользователей.
Что стоит помнить веб-разработчику: В этом случае у нас классический конфликт: удобство vs безопасность. Если веб-разработчик думает о комфорте пользователя, он может сознательно выбрать автозаполнение. Например, если важно следовать Web Content Accessibility Guidelines – рекомендациям по доступности контента для пользователей с ограниченными возможностями.
Для большинства браузеров отключить автозаполнение можно атрибутом autocompete=«off», например:
<body> <form action="/form/submit" method="get" autocomplete="off"> <div> <input type="text" placeholder="First Name"> </div> <div> <input type="text" id="lname" placeholder="Last Name" autocomplete="on"> </div> <div> <input type="number" placeholder="Credit card number"> </div> <input type="submit"> </form> </body>
Но для Chrome он не сработает. Это обходят с помощью JavaScript, вариант рецепта можно найти здесь.
- В коде сайта не задан заголовок X-Frame-Options.
Этот заголовок влияет на теги frame, iframe, embed или object. С его помощью можно полностью запретить встраивать свой сайт внутрь фрейма. Для этого нужно указать значение X-Frame-Options: deny. Или можно указать X-Frame-Options: sameorigin, тогда встраивание в iframe будет доступно только на вашем домене.
Чем опасно: Отсутствие такого заголовка можно использовать на вредоносных сайтах для кликджекинга. Для такой атаки злоумышленник создает прозрачный фрейм поверх кнопок и обманывает пользователя. Например: мошенники ставят во фрейм на сайте страницы социальных сетей. Пользователь думает, что кликает на кнопку на этом сайте. Вместо этого клик перехватывается и отправляет запрос пользователя в социальную сеть, где есть активная сессия. Так злоумышленники рассылают спам от имени пользователя или накручивают подписчиков и лайки.
Если не запретить такую возможность, злоумышленник может поставить кнопку вашего приложения на вредоносный сайт. Он может быть заинтересован в вашей реферальной программе или в ваших пользователях.
Что стоит помнить веб-разработчику: Уязвимость может появиться, если X-Frame-Options с конфликтующим значением задан на веб-сервере или балансировщике нагрузки. В этом случае сервер и балансировщик просто перезапишут заголовок, так как имеют более высокий приоритет по сравнению с кодом бэкенд-части.
Значения deny и sameorigin заголовка X-Frame-Options будут мешать работе вебвизора Яндекса. Чтобы позволить использовать iframe для вебвизора, нужно написать в настройках отдельное правило. Например, для nginx можно настроить вот так:
http{ ... map $http_referer $frame_options { "~webvisor.com" "ALLOW-FROM http://webvisor.com"; default "SAMEORIGIN"; } add_header X-Frame-Options $frame_options; ... }
- Уязвимости PRSSI (Path-relative stylesheet import).
Это уязвимость в стилях сайта. Она возникает, если для обращения к файлам стилей используются относительные ссылки вида href="/somefolder/styles.css/". Злоумышленник воспользуется этим, если найдет способ перевести пользователя на вредоносную страницу. Страница подставит относительную ссылку в свой url и имитирует обращение к стилям. Получится запрос наподобие badsite.ru/.../somefolder/styles.css/, который под видом стиля может совершать вредоносные действия.
Чем опасно: Мошенник сможет воспользоваться этой уязвимостью, если найдет еще одну дыру в безопасности. В результате так можно украсть пользовательские данные из куки или токены.
Что стоит помнить веб-разработчику: Задайте заголовок X-Content-Type-Options: nosniff. В этом случае браузер проверит тип контента для стилей. Если тип отличается от text/css, браузер заблокирует запрос.
Критичные уязвимости
- Страница с полем для пароля передается с сервера по незащищенному каналу (HTML form containing password field(s) is served over HTTP).
Ответ от сервера по нешифрованному каналу уязвим для атак типа «Man in the middle». Злоумышленник может перехватить трафик и вклиниться между клиентом и сервером, когда страница идет от сервера к клиенту.
Чем опасно: Мошенник сможет подменить страницу и прислать пользователю форму для конфиденциальных данных, которые уйдут на сервер злоумышленника.
Что стоит помнить веб-разработчику: Некоторые сайты вместо пароля присылают пользователям одноразовый код на почту/телефон. В этом случае уязвимость не так критична, но механизм усложнит жизнь пользователей.
- Отправка формы с логином и паролем по незащищенному каналу (Login Form Is Not Submitted Via HTTPS).
В этом случае от пользователя на сервер по нешифрованному каналу отправляется форма с логином и паролем.
Чем опасно: В отличие от предыдущего случая, это уже критическая уязвимость. Перехватить конфиденциальные данные проще, так как даже не нужно писать для этого код.
- Использование библиотек JavaScript с известными уязвимостями.
За время сканирования самой используемой библиотекой стал jQuery с обширным скопом версий. В каждой из версий есть хотя бы одна, а то и больше известных уязвимостей. Влияние может быть самым разным – зависит от природы уязвимости.
Чем опасно: Для известных уязвимостей есть эксплойты, например такие:
Что стоит помнить веб-разработчику: Регулярно возвращайтесь к циклу: поиск известных уязвимостей – устранение – проверка. Если вы используете устаревшие библиотеки сознательно, например для поддержки старых браузеров или для экономии бюджета, ищите возможность устранить известную уязвимость.
- Межсайтовые скрипты (XSS).
Cross-Site Scripting (XSS), или межсайтовые скрипты, – это атаки на веб-приложение, когда в результате в базе данных появляется вредонос. Если Qualys находит такую уязвимость, значит потенциальный злоумышленник может внедрить или уже внедрил в код сайта свой js-скрипт для выполнения вредоносных действий.
Хранимые XSS (Stored XSS) более опасны, так как скрипт внедряется на сервере и выполняется каждый раз при открытии в браузере атакованной страницы.
Отраженные XSS (Reflected XSS) проще проводить, так как злонамеренный скрипт можно внедрить в HTTP-запрос. Приложение получит HTTP-запрос, не проверит данные, упакует их и немедленно отправит. Если атакующий перехватит трафик и вставит скрипт вида
<script>/*+что+то+плохое+*/</script>
то от имени клиента уйдет вредоносный запрос.
Яркий пример XSS: js-снифферы, которые имитируют страницы для ввода CVC, срока действия карты и так далее.
Что стоит помнить веб-разработчику: В заголовке Content-Security-Policy используйте атрибут script-src, чтобы браузер клиента загружал и исполнял только код с доверенного источника. Например, script-src 'self' вносит в белый список все скрипты только с нашего сайта.
Наилучшей практикой считается Inline code: разрешите только inline javascript с помощью значения unsafe-inline. Такое значение разрешает использовать inline js/css, но не запрещает подключать js-файлы. В комбинации со script-src 'self' мы запрещаем выполнять внешние сценарии.
Обязательно логируйте все при помощи report-uri и смотрите на попытки внедрения в сайт.
- SQL-инъекции.
Уязвимость говорит о возможности внедрения на сайт кода SQL, который обращается непосредственно к базе данных сайта. SQL-инъекция возможна, если данные от пользователя не экранируются: не проверяются на правильность и сразу используются в запросе. Например, так происходит, если форма на сайте не проверяет соответствие ввода типу данных.
Чем опасно: Если злоумышленник введет в такую форму SQL-запрос, то может уронить базу данных или выдать конфиденциальную информацию.
Что стоит помнить веб-разработчику: Не доверяйте тому, что приходит от браузера. Защищаться нужно и на стороне клиента, и на стороне сервера.
На стороне клиента напишите проверку полей с помощью JavaScript.
Встроенные функции в популярных фреймворках также помогают экранировать подозрительные символы на сервере. На сервере также рекомендуется использовать параметризованные запросы к базам данных.
Определите, где именно идет взаимодействие с базой данных на веб-приложении.
Взаимодействие возникает, когда мы получаем какую-либо информацию: запрос с id (смена id), создание нового пользователя, новый комментарий, – новые записи в базе. Здесь могут возникать sql-инъекции. Даже если удаляем запись из базы, возможна sql-инъекция.
Общие рекомендации
Не изобретайте велосипед – используйте проверенные фреймворки. Как правило, популярные фреймворки более безопасны. Для .NET – это ASP.NET MVC и ASP.NET Core, для Python – Django или Flask, для Ruby – Ruby on Rails, для PHP – Symfony, Laravel, Yii, для JavaScript – Node.JS- Express.js, для Java – Spring MVC.
Следите за обновлениями вендора и обновляйте регулярно. Уязвимость найдут, затем напишут эксплойт, выложат в публичный доступ, и все повторится по-новой. Подпишитесь на обновления до стабильных версий от вендора ПО.
Проверяйте права доступа. Со стороны сервера всегда относитесь к вашему коду так, как будто он весь, от первой до последней буквы, написан вашим самым ненавистным врагом, желающим сломать ваш сайт, нарушить целостность ваших данных. Тем более, что иногда это действительно так.
Используйте клоны, тестовые площадки, а потом уже лейте на прод. Это поможет, во-первых, избежать ляпов и косяков на продуктивной среде: продуктивная среда приносит деньги, простой продуктивной среды критичен. При добавлении, исправлении или закрытии какой-либо проблемы стоит проводить работы в тестовом окружении, потом проверять функциональность и найденные уязвимости, а затем уже планировать работы с продуктивной средой.
Защищайте веб-приложение при помощи Web Application Firewall и интегрируйте с ним отчеты от сканера уязвимостей. Например, в DataLine в качестве связки сервисов используются Qualys и FortiWeb.
mayorovp
В пункте по XSS я почему-то не вижу рекомендации использовать защищенные by desing технологии и без особых причин не формировать HTML-разметку конкатенацией строк или шаблонными строками.
dataline Автор
Все так. Защищенные by design технологии мы вынесли в общие рекомендации — это можно везде добавить.
Можно было бы еще добавить, что в разных веб-фреймворках для подобных задач есть специальные методы, которые делают это безопасно. Например, в Spring MVC — класс HtmlUtils, который содержит пачку утилитных функций для работы с HTML.
mayorovp
В таком случае список "проверенных фреймворков" лучше бы сократить. Например, ASP.NET WebForms к XSS как раз очень уязвим, в отличии от использующих Razor ASP.NET MVC и ASP.NET Core
Признаком кривого дизайна как раз и являются HtmlUtils и подобные им "безопасные" способы работы с HTML.
dataline Автор
Про ASP.NET MVC и ASP.NET Core уточнили в тексте, спасибо. Конечно же, мы имели в виду _современные_ фреймворки.
Про HtmlUtils — да, возможно, не самый удачный пример здесь. В тексте статьи только универсальное, либо проверенное на собственном опыте. Поэтому, конечно, не все возможные случаи рассмотрены.