Бизнес-логикаПентестУязвимостиВеб-безопасностьРазбор

Поиск ошибок бизнес-логики в веб-приложениях или почему следует звать пентестера

Глубокий анализ уязвимостей бизнес-логики в веб-приложениях и их классификация. Почему современные сканеры не справляются с поиском таких уязвимостей.

Поиск ошибок бизнес-логики в веб-приложениях или почему следует звать пентестера

Поиск ошибок бизнес-логики в веб-приложениях или почему следует звать пентестера

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

Мотивацией к написанию данной статьи послужило осознание частого игнорирования ошибок бизнес-логики на системном уровне в различного рода статьях и литературе, посвященной поискам уязвимостей в веб-приложениях. Ведь в самом деле, в одноименной классификации OWASP Top 10, на которую часто ссылаются, когда затрагивают веб-уязвимости, отсутствует явное упоминание данного понятия, хотя некоторые из указанных там уязвимостей, в некоторых случаях, можно причислить к оным.

В упомянутой классификации данное понятие можно встретить только в пункте A04:2021-Insecure Design, который описан достаточно абстрактно, а в списке сопоставленных CWE как раз указан идентификатор «CWE-840 Business Logic Errors», который стоит в одном ряду с «CWE-256 Unprotected Storage of Credentials» и «CWE-257 Storing Passwords in a Recoverable Format» и т.д.. В этом, как мне кажется, кроется главная проблема, ведь ошибки бизнес-логики встречаются чаще, а также менее тривиальны и поэтому требуют своей собственной классификации, а также дополнительного отдельного изучения исследователями и разработчиками.

Содержание

Что такое ошибки бизнес-логики?

Уязвимости бизнес-логики — это недостатки в проектировании и реализации приложения, которые позволяют злоумышленнику вызвать непреднамеренное поведение. Это потенциально позволяет злоумышленникам манипулировать легитимной функциональностью для достижения вредоносной цели. Эти недостатки, как правило, возникают из-за неспособности предвидеть возможные необычные состояния приложения и, как следствие, неспособности безопасно их обрабатывать. (https://portswigger.net/web-security/logic-flaws)

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

Таким образом, мы приходим к тому, что любую нестандартную логику приложения необходимо упрощать и приводить к более «очевидным» и «проверенным» моделям. Так как «необычные» реализации, например, таких механизмов как: аутентификация, покупка товара на сайте или запрос обратной связи, и т.д., даже в условиях, отсутствующих брешей на первый взгляд, могут попасться на глаз хакеру, исследующему ваше приложение.

Классификация ошибок бизнес-логики

Конечно, нет единственного правильного ответа на вопрос, «Как сделать безопасно?». Что касается ошибок бизнес-логики, можно выделить лишь основные типы и довольно абстрактные рекомендации по реализации защиты от них. Классифицировать упомянутые уязвимости можно по объектам воздействия следующим образом (https://xakep.ru/2015/01/31/logic-fails-top-2014/):

Манипуляция пользовательскими данными

На сайте test.ru есть стандартный функционал — добавление товаров в корзину. С точки зрения клиента всё выглядит просто: выбираешь товар, указываешь количество и видишь цену. Но в этом примере серверная часть не выполняет достаточно жёсткую валидацию входящих данных и напрямую принимает параметры из запроса. Это создаёт риск несогласованности между тем, что показал интерфейс, и тем, что фиксируется на сервере.

При перехвате через прокси можно увидеть примерно такой запрос:

POST /buy.php?id=12&quantity=1&price=50 HTTP/1.1
Host: test.ru
Content-Type: application/x-www-form-urlencoded
...

Здесь ключевые поля — id, quantity, price. Именно их подмена или изменение на стороне клиента может привести к тому, что сервер примет некорректные данные. В нормальной архитектуре цена и другие критичные поля должны определяться сервером по id товара, а не доверяться значениям, пришедшим от пользователя.

Наблюдаемые признаки отсутствия валидации:

  • сервер возвращает успешный ответ (HTTP 200) при явном рассогласовании цены;
  • в базе данных появляются записи с ценой, отличающейся от ожидаемой;
  • учёт остатков или финансовые отчёты показывают несоответствия после операций;
  • ответы сервера не содержат дополнительных проверок статуса платежа или подтверждения от платёжного шлюза.

Последствия такой уязвимости выходят за рамки простой «игры с ценой». Это может привести к ошибочным записям в системе учёта, некорректным состояниям заказов и искаженному представлению о транзакциях. При анализе важно фиксировать запросы и ответы, сравнивать значения, которые отображает интерфейс, с теми, что приходят на сервер, и смотреть на последовательность событий в логах (время, коды ответов, изменения состояния заказа).

Манипуляция функционалом веб-приложения

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

Например, вы оформляете заказ на маркетплейсе. Процесс выглядит просто и понятно:

  1. Добавляете товар в корзину.
  2. Оплачиваете корзину.
  3. Подтверждаете заказ.

Так задумано. Но если сервер не проверяет, прошла ли оплата, пользователь может напрямую вызвать шаг подтверждения, минуя оплату. И система, не замечая подвоха, принимает этот запрос, считая, что всё сделано правильно.

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

На практике подобная уязвимость может привести не только к обходу оплаты, но и к другим проблемам: оформлению недействительных заказов, доступу к закрытым разделам, или даже к изменению чужих данных. Поэтому важно проверять каждый шаг обработки запроса на стороне сервера — независимо от того, что делает клиентская часть приложения.

Пример: уязвимость в интеграции PayPal

Некоторые интеграции PayPal принимали IPN/webhook-уведомления о платеже без надёжной валидации (payment_status, txn_id и т.д.), и в результате обработчик мог пометить заказ как «оплачен» только по пришедшему POST-запросу, даже если реальной транзакции не было. Этот класс ошибок хорошо иллюстрируется на примере плагина GloBee для WooCommerce (mishandled IPN).

Пример упрощённого формата POST-уведомления (IPN/webhook), который получал слушатель:

POST /paypal/ipn-listener HTTP/1.1
Host: shop.example
Content-Type: application/x-www-form-urlencoded

txn_id=ABC1234567890
&payment_status=Completed
&mc_gross=49.99
&mc_currency=USD
&invoice=INV-2025-0001
&receiver_email=seller@example.com
&payer_email=attacker@example.org
&custom=order_id:12345

Правильная практика описана в документации PayPal: слушатель должен подтверждать подлинность уведомления у PayPal (verify postback / verify webhook signature) и сверять сумму/получателя перед изменением статуса заказа.

GitHub Issue: GloBee WooCommerce Plugin

Манипуляция незащищенными страницами

Для объяснения следующего типа уязвимостей рассмотрим следующий пример. На сайте есть основная точка загрузки изображений — /v1/upload. На ней работают фильтры: проверка типа и размера файла, блокировка запрещённых расширений, сканирование содержимого. Но при анализе API обнаружилась альтернативная (вспомогательная или тестовая) конечная точка /v2/upload, где эти проверки отсутствуют или выполнены поверхностно.

Если /v2/upload принимает файл без тех же валидаций, это говорит о несогласованности контролей на сервере. Одна и та же операция — загрузка файла — возвращает разный уровень безопасности в зависимости от выбранного endpoint'а.

Типичные признаки проблемы:

  • успешный ответ при загрузке запрещённого типа файла;
  • отсутствие фильтрации по расширению или MIME;
  • отсутствие ошибок/предупреждений в ответах.

Последствия выходят за рамки «непоследовательности» — незакрытая точка становится каналом для загрузки неподходящих или вредоносных файлов, искажает представление о реальных гарантиях безопасности приложения. При разборе инцидента важно фиксировать различия между точками входа, сравнивать ответы, заголовки и коды статуса, а также проверять логи на предмет аномалий.

Реальный пример из практики

В качестве примера — случай, найденный нашей командой (название компании не разглашается в соответствии с NDA). При пентесте было обнаружено, что у разработчиков осталась незакрытая конечная точка для смены пароля, не требовавшая аутентификации. Это позволило не аутентифицированному пользователю изменить пароль по известному id:

PATCH /v2/auth/<id>/change_password HTTP/2
Host: vulnerable.host
...

{"Password": "123"}

При этом, в веб-приложении в /v1 версии API был реализован похожая конечная точка, но которая была реализована с необходимыми механизмами безопасности.

Такая уязвимость — серьёзный риск: она даёт прямой путь к компрометации аккаунтов и подрывает доверие пользователей. Даже если основная логика защищена, «забытие» вспомогательных endpoint'ов сводит на нет эти меры.

Манипуляции проверками на стороне клиента

Это распространённая проблема, когда права доступа реализованы только на стороне клиента — в браузерном коде — а сервер не выполняет собственных проверок. Иногда разработчики добавляют в JavaScript проверки видимости кнопок или маршрутов: если флаг isAdmin ложен, кнопка «Админ панели» не показывается. Но скрытие в интерфейсе — не то же самое, что реальная защита.

Типичная картина: в коде клиента есть условие, которое решает, показывать ли ссылку или форму. Примерно так:

if (user.role === 'admin') {
    showAdminPanel();
}

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

Признаки такой уязвимости:

  • элементы интерфейса скрыты, но те же конечные точки API доступны при прямом обращении;
  • при модификации параметров запроса сервер отвечает так же, как для «публичных» пользователей;
  • в коде фронтенда видны явные проверки прав без соответствующих проверок в ответах сервера.

Последствия — понятны: пользователь может выйти за рамки изначально спроектированной модели разграничения доступа, что в результате может привести к возможности изменить данные или получить доступ к административным операциям. При разборе инцидента важно фиксировать как клиентские проверки, так и поведение сервера при прямых запросах, чтобы понять, где именно отсутствует надёжная серверная авторизация.

Пример: PhpWebGallery 1.0

В PhpWebGallery 1.0 была уязвимость, при которой административный доступ можно было получить простым установлением специальной куки — photo_login=pseudo. То есть проверка прав полагалась на значение в клиентской куке, и злоумышленник мог подделать её и получить доступ к админ-функциям.

GET /admin/isadmin.php HTTP/1.1
Host: vulnerable.example
Cookie: photo_login=pseudo; session=eyJ...
User-Agent: Mozilla/5.0

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

Манипуляция параллельными сеансами

Представьте: несколько параллельных запросов «мчатся» к одному и тому же серверному действию, и результат зависит от того, кто из них добежит первым. В веб-приложениях это проявляется как классическая race condition — ошибки, возникающие из-за отсутствия атомарности операций или корректной синхронизации.

Один из наглядных сценариев — применение купона в интернет-магазине. Схема проста и стара как мир:

  1. Клиент отправляет запрос на применение купона.
  2. Сервер вычитает рассчитанную скидку и обновляет стоимость корзины.
  3. Сервер затем проверяет, не был ли купон использован ранее для этой корзины.

Если эти шаги не выполняются атомарно, между записью скидки и проверкой существует «окно» — доли секунды, в которых другой параллельный запрос может пройти по тому же пути и применить скидку повторно. При множественных почти-одновременных запросах итогом может стать многократное применение одной и той же скидки или конфликтующие состояния заказа.

Техника синхронизации по последнему байту

Интересно: в таких сценариях встречаются техники, которые пытаются синхронизировать много запросов так, чтобы они пересекались именно в этом окне (иногда это называют «синхронизацией по последнему байту»).

Упрощенно, данная техника базируется на том, что клиент может отправить N HTTP пакетов, но предварительно из каждого убрав по 1 байту. И все эти оставшиеся байты, затем отправляются в одном TCP пакете. К тому моменту, когда отправляется «трейлер», сервер уже собрал у себя кэше отправленные ранее части пазла, поэтому в момент получения последнего, потоки начинают выполнятся синхронно. И если у сервера нет проблем с параллельной обработкой нескольких потоков, то как раз и получается, что потоки синхронно достигают соответствующего участка кода с применением скидок.

Важно понимать — речь не о магии, а о том, что асинхронная природа сети и отсутствие строгих проверок на сервере создают шанс для рассогласования логики.

Признаки наличия race-условий:

  • необъяснимые дублирующиеся скидки в логах;
  • журналы, где два-три запроса приходят с очень близким временем и приводят к разным исходам;
  • несогласованность состояния корзины и записей в базе данных сразу после серии параллельных запросов.

Последствия — серьёзные: финансовые потери, неверный учёт остатков, некорректные состояния заказов и затруднённая трассировка инцидентов, когда результаты зависят от точного порядка поступления запросов.

Это хорошая иллюстрация того, как простой, на первый взгляд, бизнес-процесс перестаёт быть детерминированным в условиях параллелизма — и почему при проектировании операций с изменением состояния нужно думать о порядке выполнения и согласованности данных.

Что могут предложить современные сканеры веб-приложениям?

Современные инструменты для поиска уязвимостей в веб‑приложениях обычно используют два основных подхода:

  • Сигнатурный (распознавание по баннерам/версиям) — быстрый профиль целей;
  • Активное тестирование / эксплуатация — отправка полезных нагрузок для подтверждения уязвимостей.

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

Сигнатурные сканеры: что это и зачем

Сигнатурный подход ориентирован на скорость и масштаб. Инструмент запрашивает сервис, получает баннер или стандартный ответ и сопоставляет его с базой известных версий и уязвимостей. Это удобно для первичной разведки и обнаружения «1‑day» уязвимостей.

Пример инструмента: nmap (NSE‑скрипты), WhatWeb, Wappalyzer (для отпечатков стеков).

Плюсы:

  • Высокая скорость сканирования
  • Массовый охват большого числа целевых хостов
  • Удобство агрегации и фильтрации по версиям

Минусы:

  • Не находит 0‑day уязвимости
  • Возможны ложные срабатывания при одинаковых баннерах
  • Слаб в поиске уязвимостей бизнес‑логики

Когда использовать: быстрый аудит поверхности, инвентаризация сервисов, первичный триаж.

Активное тестирование: шаблоны и глубокие инструменты

Активное тестирование предполагает реальную отправку потенциально вредоносных payload'ов и анализ ответов. Внутри этого класса есть несколько подтипов.

Шаблонные движки

Пример: nuclei. Работают на базе описаний (template) — каждый шаблон задаёт точку запроса, полезную нагрузку и условие распознавания уязвимости. Удобны для массового поиска по списку известных CVE и сценариев.

Особенности: высокая скорость подтверждения известных случаев, гибкость шаблонов (YAML/JSON), возможность массового запуска в CI/CD.

Инструменты для конкретных классов уязвимостей

Примеры: sqlmap (SQL‑инъекции), XSStrike / XSSer (XSS), DirBuster/gobuster (директории), ffuf (fuzzing).

Особенности: специализированные техники для получения доказательств (например, вытягивание данных через SQLi), лучше подходят для воспроизведения и подтверждения уязвимости.

Динамические сканеры и прокси

Примеры: OWASP ZAP, Burp Suite, Acunetix, Nessus (Tenable) Web App Scanning.

Что умеют: краулинг, интерактивный анализ, аутентифицированные проверки, интеграция с CI, отчётность. Часто включают возможности для написания собственных плагинов/скриптов.

Недостатки: потенциальная нагрузка на тестируемое приложение; сложнее настройка; коммерческие лицензии для полного набора функций.

Аутентифицированные vs. неаутентифицированные сканы

Разделение по наличию учетных данных критично. Неаутентифицированный скан показывает поверхность, доступную анониму. Аутентифицированный (credentialed) скан — даёт картину того, что может сделать реальный пользователь или привилегированный аккаунт. Бизнес‑логика, ошибки авторизации и внутренние API чаще видны только при сканировании с логином.

Пример: админ‑контролы или скрытые API часто не доступны при внешнем сканировании, но легко обнаруживаются при использовании тестовой учётной записи.

Практические сценарии использования и цепочка проверки

Профилирование: nmap / WhatWeb / пассивный краул — быстро выявляют стек и версии. Это помогает приоритизировать цели.

Массовый фильтр: nuclei с обновлённой коллекцией шаблонов — для массовой проверки известных сценариев и CVE.

Фокусные тесты: sqlmap, XSStrike, ffuf по подозрительным параметрам — попытка получить доказательство уязвимости.

Аутентифицированный/ручной анализ: OWASP ZAP, Burp и ручной аудит бизнес‑логики для выявления уязвимостей авторизации и логики.

Такой поток работы оптимизирует время: от широкой разведки к доказательной проверке.

Сводная таблица сканеров

Подход Примеры инструментов Что делает Плюсы Минусы
Сигнатурный (banner/version) nmap, WhatWeb, Wappalyzer Распознаёт сервисы/версии по баннерам Очень быстро, масштабно, полезно для триажа Не находит 0‑day, ложные срабатывания по баннерам
Шаблонный (templates) nuclei (+ шаблоны), detectify Шлёт заранее описанные payload'ы по шаблонам Автоматизация массовых проверок, гибкость Зависит от качества шаблонов; необходим постоянный апдейт коллекции
Фокусный sqlmap, XSStrike, ffuf Глубокая проверка конкретных классов (SQLi, XSS, fuzzing) Даёт доказательства и PoC, высокое качество обнаружения Требует времени и аккуратной настройки
Динамический/прокси OWASP ZAP, Burp, Acunetix, Nessus Краулинг, активные сканы, аутентифицированные тесты Мощный функционал, отчётность, CI‑интеграция Нагрузка на приложение; лицензии; сложнее конфигурировать

Оптимальный подход комбинирует методы: профилирование, массовая проверка шаблонами и углублённая проверка конкретных уязвимостей, дополняемая ручным аудитом бизнес‑логики. Такой процесс даёт высокий охват и снижает риск упустить серьёзные ошибки.

Использование сканеров для поиска уязвимостей бизнес-логики

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

Легенда:

  • Средне — сканер может найти проблему в редком, но возможном случае (обнаружит конечную точку, отправит модифицированные данные и наткнётся на проявление логики);
  • Низко — шанс небольшой; требуется ручная доработка;
  • Нет — не находит.
Уязвимость (по классификации) Сигнатурные (nmap/WhatWeb) Шаблонные (nuclei) Специализированные (sqlmap/XSStrike/ffuf) Динамич./Прокси (ZAP/Burp)
Манипуляция порядком действий (order-flow bypass) Нет Если есть соответствующий шаблон Нет Низко
Манипуляция параметрами (price/quantity tampering) Нет Средне Средне
Забытая/незащищённая точка загрузки (/v2/upload) Низко Средне Средне
Клиентская проверка прав (client-side auth bypass) Нет Низко Средне
Race condition (гонки, многократное применение купона) Нет Нет Нет Нет

Выводы

Автоматические сканеры дают полезные подсказки, но лишь в редких случаях сами выявляют ошибки бизнес-логики — чаще они отмечают потенциальные точки входа (эндпоинты, параметры, незакрытые upload). Шаблонные и динамические инструменты иногда попадают на проблему, но надёжное подтверждение требует целевых тестов и ручного анализа.

Следовательно, для поиска и верификации уязвимостей бизнес-логики нужно сочетать автоматический триаж с интерактивным аудитом и аутентифицированными сценариями. Именно поэтому участие квалифицированного пентестера остаётся критически важным для обеспечения безопасности веб-приложений.