Через меня и моих коллег прошло более сотни проектов по пентесту крупных компаний в сфере финансов, госструктур, промышленности и ритейла. Мы проанализировали наиболее часто встречающиеся уязвимости веб-приложений и собрали топ-6 на основе своего опыта.
В материале расскажем, какие «болячки» бывают у веб-приложений чаще всего, как их находят и эксплуатируют хакеры и как от них вылечиться.
1. Инъекции в HTML и JavaScript
Javascript-инъекции и HTML-инъекции давно известны в кибербез-сообществе, но всё равно не перестают встречаться.
Через такие уязвимости можно подменить внешний вид сайта, встроить фишинговую форму, украсть cookies, провести редирект на вредоносный ресурс и выполнить ряд других действий от имени пользователя. Отдельно можно выделить Form Hijacking — когда хакер подменяет форму и провоцирует пользователя отправить конфиденциальные данные злоумышленникам.
Эти уязвимости в основном появляются из-за небезопасной обработки ввода пользователя или неправильного использования библиотек для разработки сайта.
Как защититься
Чтобы защититься от HTML- и JavaScript-инъекций, в первую очередь нужно жёстко контролировать пользовательский ввод: экранировать или удалять опасные символы перед выводом в HTML. Использовать готовые шаблонизаторы и библиотеки с автоэкранированием, вместо ручной вставки значений в разметку. Настраивать Content Security Policy (CSP), чтобы ограничить выполнение стороннего кода. Не забывать проверять не только поля форм, но и заголовки, cookies, параметры URL и API — любые данные, приходящие от пользователя.
2. Раскрытие информации через IDOR, сообщения об ошибке, доступ к swagger и graphql
IDOR (Insecure Direct Object Reference) — когда пользователь может получить доступ к данным других пользователей, просто изменив идентификатор в URL. А ошибки сервера или открытые API-интерфейсы (Swagger, GraphQL) могут раскрывать внутреннюю логику приложения.
Иногда сервис неадекватно реагирует на данные, которые он не ожидал. Например, в текстовое поле можно ввести число. Если разработчик не позаботился об обработке ошибок, то приложение может выдать ошибку пользователю, раскрывая внутреннее устройство сервиса. И если обычному человеку это может ни о чем не говорить, то злоумышленнику будет проще подобрать вредоносные нагрузки.
Также в последнее время часто встречаются приложения, использующие технологию GraphQL для работы с API, но мало кто заботится об отключении такой функции, как интроспекция. Эта функция позволяет получить полное описание схемы API GraphQL, причём для этого необязательно быть авторизованным пользователем. Открытый доступ к swagger также позволяет за минимальное количество времени получить представление об используемых API-методах, и, соответственно, ускоряет их компрометацию.
Как защититься
Чтобы защититься от раскрытия информации через IDOR, сообщения об ошибках, доступ к Swagger и GraphQL, нужно реализовать несколько уровней контроля:
- Для IDOR: проверить права доступа на каждый объект, а не только на уровне маршрута. Не доверять пользовательским ID — даже если они выглядят как случайные строки, они могут быть предсказуемыми.
- Для сообщений об ошибках: отключить подробные сообщения об ошибках в проде. Не показывать stack trace, SQL- или system-ошибки пользователю — лучше использовать кастомные сообщения или коды ответа без лишней информации.
- Для Swagger и GraphQL: ограничить доступ к Swagger-интерфейсу только авторизованным пользователям или полностью отключить его в проде. В GraphQL отключить интроспекцию, если она не нужна, и внедрить ограничения по типу rate limiting и depth limiting, чтобы предотвратить утечки схемы и перегрузку сервера.
3. Уязвимости формы аутентификации
Форма аутентификации является клондайком для хакеров, так как её уязвимость может вести за собой серьёзные последствия в виде нарушений разграничения доступа, возможности получить доступ к аккаунтам пользователей и администраторов.
Такие уязвимости находят через перебор пользователей и паролей. И если система возвращает разные сообщения об ошибках при неверном логине и пароле — это позволяет определить, какие логины существуют. Дальше идёт подбор. Через форму восстановления пароля можно отправить десятки писем с подменой адресов и ссылок. Разные ответы сервера также можно найти и в форме восстановления пароля, там в поле в основном вводится почта пользователя, соответственно можно собрать список почт для использования в фишинге.
Форма восстановления пароля может таить в себе ещё и возможность DOS-атак.
Если разработчики не предусмотрели ограничения, злоумышленник может отправлять огромное количество писем на один и тот же адрес, модифицируя его (например, user@mail.com, user+1@mail.com, user+2@mail.com). А если на сайте есть ещё и уязвимость, связанная с обработкой заголовка Host, ситуация становится ещё серьёзнее: атакующий может подменить адрес сайта в письме. Тогда пользователь получит письмо со ссылкой на внешний, подконтрольный злоумышленнику ресурс — и передаст свой код подтверждения не тому, кому нужно.
Как защититься
Чтобы защитить форму аутентификации от уязвимостей, важно реализовать несколько ключевых мер:
- Унифицировать ответы сервера при неверных логине и пароле — сообщения об ошибке не должны давать понять, существует ли такой пользователь.
- Ввести ограничения на количество попыток входа — использовать rate limiting, капчу или блокировку IP/учётки.
- Обеспечить жёсткую политику паролей: минимальную длину, наличие цифр, букв разных регистров и специальных символов.
- Защитить форму восстановления пароля от enumeration и флуда — проверять частоту запросов, использовать токены с ограничением по времени и одноразовые ссылки.
- Исключить возможность Host header injection — проверять заголовок Host на соответствие допустимому списку доменов при генерации ссылок в письмах.
4. Небезопасная загрузка файлов
Если удаётся загрузить исполняемый файл и обратиться к нему через приложение как к картинке, то можно получить исполнение кода. Это может стать крайне серьёзной уязвимостью.
К счастью, современные приложения хорошо фильтруют передаваемые файлы и меняют расширения, так что до критической уязвимости редко доходит. Но если название файла отражается где-то на сайте, то при обходе фильтрации можно добиться XSS — то есть получить доступ к данным пользователя. Так безобидная фотография собачки может стать причиной кражи аккаунтов пользователей веб-приложения.
Как защититься
Чтобы предотвратить уязвимости, связанные с загрузкой файлов, необходимо:
- Ограничить типы допустимых файлов — проверять MIME-тип и расширение, использовать белые списки форматов.
- Изменять имена загружаемых файлов и сохранять их в изолированной директории без права исполнения.
- Исключить возможность обработки файлов как кода — отключить выполнение скриптов в директории загрузки.
- Фильтровать или экранировать имена файлов, если они отображаются на сайте, чтобы исключить XSS.
- Проверять содержимое файла, а не полагаться только на расширение — особенно если система обрабатывает изображения, документы и архивы.
5. Race Condition
Race Condition — это тип уязвимости, возникающий, когда несколько запросов обрабатываются системой одновременно и конкурируют за доступ к одному и тому же ресурсу. Если система не учитывает возможность одновременного выполнения, это может привести к непредсказуемому поведению: от дублирования операций до обхода логики безопасности.
На практике Race Condition чаще всего проявляется в функционале, связанном с транзакциями, регистрацией, восстановлением пароля, начислением бонусов или проверками ограничений. Например:
- При отправке нескольких запросов на покупку одновременно — может быть списано меньше средств, чем нужно, а товар всё равно выдан.
- При регистрации или смене пароля — можно перехватить аккаунт, отправив запрос в момент между проверкой и записью данных.
- При начислении бонусов — можно получить больше наград, чем разрешено, отправив пачку идентичных запросов одновременно.
Как защититься
Чтобы предотвратить ошибки, связанные с Race Condition, следует:
- Проектировать критичные операции как атомарные — использовать транзакции, блокировки (mutex) или очереди при работе с чувствительными данными.
- Внедрить контроль состояния объектов — отслеживать, была ли уже обработана заявка, подтверждён ли код, завершена ли операция, прежде чем выполнять повторное действие.
- Ограничить количество параллельных запросов — применять rate limiting и устанавливать таймауты между повторными действиями.
- Тестировать бизнес-логику на предмет одновременного доступа — моделировать конкурентные сценарии в процессе QA и пентестов.
6. Раскрытие информации об исходном коде на открытых источниках
Некоторые сервисы создаются подрядными работниками и публикуются на github, чтобы потенциальные работодатели видели, что у программиста есть живые проекты. В открытых репозиториях часто указывается название продукта, для которого был написан код.
Так через поиск можно найти исходники приложений, а иногда и дефолтные учетные данные. Последнее время github активно работает над выявлением утечек данных через открытые репозитории, что влияет на общую безопасность, но за этим всё равно необходимо следить самостоятельно.
Как защититься
Чтобы избежать утечек кода через открытые репозитории, желательно:
- Настроить автоматический поиск чувствительных данных (ключей, паролей, токенов) в коде перед коммитом — можно использовать инструменты типа Git-secrets, TruffleHog или GitGuardian.
- Разделить открытые и закрытые репозитории — не выкладывать публично ничего, что может содержать упоминания о внутренней инфраструктуре, доменах, конфигурациях.
- Регулярно проводить мониторинг утечек с помощью сервисов наподобие GitHub Advanced Security или сторонних решений.
- Подписывать NDA и транслировать сотрудникам и подрядчикам риски публикации кода. Объяснять, какие данные не должны попадать в открытые репозитории, и по возможности согласовывать публикации, связанные с рабочими проектами.
Вывод
Большинство успешных атак начинаются не со сложных zero-day уязвимостей, а с простых и давно известных ошибок.
Контроль, дисциплина и регулярные аудиты позволяют избежать серьёзных последствий.