
Мы как-то писали про SSRF-атаку, которая входит в список наиболее распространенных уязвимостей OWASP Top 10. Однако мир уязвимостей намного разнообразнее и, конечно же, не ограничивается этим списком. Сегодня мы хотим рассказать про уязвимости, связанные с бизнес-логикой. Что в них необычного? Это как доказать, что 2+2=5. Последовательность действий кажется правильной, все операции разрешенными, а результат совсем не тот, который закладывался при разработке. Но мы же знаем, что в доказательстве есть ошибки! Рассмотрим, как подобные задачки решаются при анализе защищенности и какие неожиданные результаты можно получить, используя обычную функциональность приложений.
Бизнес-логика и какие уязвимости в ней могут быть
Для начала немного теории. Бизнес-логика обеспечивает выполнение задач, которые закладывались при проектировании приложения, то есть определяет его поведение при всех возможных сценариях использования. В свою очередь, уязвимости бизнес-логики связаны с недостатками в архитектуре или ошибками, допущенными при реализации логики приложения. Это может в итоге привести к взаимодействию с приложением по непредусмотренному разработчиками сценарию.
Вот простой пример. Для защиты от атак подбора пароля в приложении реализован механизм CAPTCHA. При работе через веб-интерфейс после трех неудачных попыток ввода требуется решить типичную задачу с картинками. Однако при прямой отправке запросов на сервер никаких ограничений не предусмотрено. То есть фактически CAPTCHA никак не защищает от атак подбора. Как так получилось, нам остается только догадываться. Возможно, разработчики решили, что никто не будет напрямую обращаются к API. А зря!

Уязвимости бизнес-логики отличаются от большинства других уязвимостей:
-
они разнообразны, можно сказать, уникальны для каждого приложения. Это связано с особенностями работы и направленностью каждого отдельного приложения;
-
их трудно обнаружить автоматизированными сканерами. Отсутствие общих схем классификации и способов обнаружения, а также необходимость понимания предметной области делает уязвимости бизнес-логики недоступной целью для автоматизированных сканеров. Например, заметив в корзине покупок товар с отрицательной стоимостью, человек понимает: что-то пошло не так. Но для сканера – это просто числа;
-
они предполагают манипуляции легитимной функциональностью приложений. В примере выше, для обхода CAPTCHA не было использовано никаких дополнительных инструментов и действий, а только запрос, который использует само приложение.
Нет единой причины появления ошибок бизнес-логики, как нет и единого шаблона их обнаружения. Это и делает поиск подобных уязвимостей сложным и интересным одновременно.

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

Обратим внимание на параметр id и поле password, которое содержит пароль пользователя(!). Пробуем заменить идентификатор на любое другое число – в ответе получаем данные другого пользователя. Осталось дело за малым, автоматизируем перебор идентификаторов и собираем список пользователей и их паролей.
Представленный пример содержит сразу две уязвимости:
-
небезопасное управление паролями – их хранение в открытом виде и передача пользователям;
-
небезопасные прямые ссылки на объекты – обращение к объектам на основе полученного от пользователя идентификатора.
Управление паролями – это отдельная тема, которой мы не будем касаться в рамках текущей статьи. А вот на небезопасных прямых ссылках на объекты остановимся подробно. Безусловно, подобные уязвимости также относятся к недостаткам контроля доступа (OWASP Top 10, A01:2021 – Broken Access Control) и могут быть расценены как пропущенные проверки прав. Однако посмотрим на проблему именно со стороны бизнес-логики.
Эксплуатация уязвимости кажется тривиальной, однако сама она не так проста. Вернемся к истокам. Предположим, нам необходимо реализовать функциональность профиля. Начнем с общего сценария ее использования. Пользователь хочет посмотреть свой профиль и выбирает соответствующий пункт в меню, после чего на экране появляется страница с его данными. При этом если неизвестно, какой пользователь обратился, сначала он перенаправляется на форму аутентификации. Кажется, что все хорошо: пользователю будет доступен только его профиль. Приступаем к реализации.


И вот уже появляется ошибка. При запросе данных (/api/person?id=22) не проверяются ни сессия, ни права пользователя. Поэтому представленный в начале запрос на получение паролей успешно реализуется. При этом изначальные требования о том, что неаутентифицированный пользователь не может просмотреть страницу профиля – выполняется.
Как так получилось? При проработке сценариев использования не было учтено возможное прямое обращение к API. Конечно, обычно мы работаем с приложением через браузер и взаимодействуем с визуальными элементами, и одной проверки сессии в этом случае достаточно. И это одна из самых распространенных ошибок бизнес-логики – неверные предположение о действиях пользователей. Чтобы ее исключить, необходимо проверять права при каждом обращении к API. А это, согласитесь, уже не самая простая задача.

Небезопасные прямые ссылки на объекты одна из наиболее распространенных уязвимостей в веб-приложениях на протяжении последних лет. В проектах по анализу защищенности мы сталкиваемся с разными ее проявлениями: чтение данных, удаление и копирование объектов и многое другое. При этом подобные уязвимости редко встречаются в единичных экземплярах.
Как мы уже говорили выше, такие ошибки сложно обнаружить автоматизированными сканерами. Правда, технологии не стоят на месте, и сканеры уже умеют обнаруживать подобные уязвимости, хоть и с большим уровнем ошибок первого и второго рода. Поэтому пока лучший способ обнаружить небезопасные прямые ссылки на объекты – ручной анализ. При этом стоит помнить, что идентификаторы – это не только инкрементальные числа. Название файлов, методов, уникальные идентификаторы (GUID) – небезопасные прямые ссылки на объекты могут быть везде. Поэтому необходимо анализировать всю функциональность приложения и проверять полученные результаты по установленной матрице доступа.
Доверяй, но проверяй
Неверные предположения о действиях пользователей также часто становятся причиной избыточного доверия клиентской части приложения. Давайте разберем, почему же клиенты не заслуживают слепого доверия.
Возможно, многие знают хрестоматийный пример изменения цены товара в запросе. Это демонстрация подделки параметров (Parameter Tampering) – достаточно простой атаки, которая также направлена на бизнес-логику приложений. Основная ее идея в том, что разработчики используют скрытые поля на странице или другие зафиксированные параметры как данные из достоверных источников. Стоит отметить, что это могут быть также cookie-файлы, значения заголовков и т.д. То есть все, что может быть изменено при отправке запроса.

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

Обычно параметр balance используются только для удобства пользователя, чтобы тот смог увидеть свои бонусы и доступные товары. При этом ничего не мешает изменить значение этого параметра в ответе и посмотреть, что произойдет. Изменить ответ на запрос можно с помощью перехватывающего прокси, например, Burp Suite.


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

Некорректные проверки прав также часто встречаются в одностраничных приложениях (Single Page Application, SPA), в которых в зависимости от уровня привилегий отображается тот или иной интерфейс. В совокупности с ранее описанной уязвимостью (небезопасные прямые ссылки на объекты) это представляет значительную опасность для всего приложения.

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

Вокруг да около
Предыдущие примеры так или иначе были связаны с проверкой прав и возможностей пользователей. Однако ошибки бизнес-логики не только про это. Далее разберем, как отсутствие определенных ограничений может привести к финансовым потерям, иногда даже достаточно крупным.
Как отмечалось выше, логические уязвимости зачастую появляются в сложных приложениях. Например, онлайн-банки, которые сложны и многокомпонентны по своей природе. Интерес у злоумышленников к уязвимостям в таких приложениях подогревается возможностью кражи денег здесь и сейчас. При проведении работ по анализу защищенности мы также ищем ошибки, которые позволяют быстро получить деньги. Одной из наиболее известных уязвимостей подобного типа является ошибка округления сумм денежных средств.
В качестве простого примера рассмотрим перевод денежных средств в другую валюту. Не будем привязываться к какой-либо реальной валюте и сделаем следующее допущение:
|
1 солярик |
=> |
100 рублей |
|
1 минисолярик |
=> |
0.01 солярика или 1 рубль |
Итак, попробуем купить 1 солярик меньше, чем за 100 рублей.

Проведенная схема – это пример атаки на округление. Действительно, 40 копеек – это 0.004 солярика, что по обычным правилам округления меньше 0.01 солярика, то есть минимальной единицы. А вот 57 копеек – 0.0057 солярика и по обычным правилам округления получаем 0.01 солярика или 1 минисолярик. Подобная атака известна далеко не первый год, и ей все еще подвергаются банковские приложения.
Описанная уязвимость также относится к ошибкам бизнес-логики, поскольку связана с некорректными требованиями к входным данным. При совершении подобных операций необходимо устанавливать ограничения на сумму перевода или совершать округление в меньшую сторону.
Стоит отметить, что ошибки округления встречаются не только в банковских приложениях. В целом работа с числами с плавающей точкой может сопровождаться неожиданными результатами. Поэтому стоит всегда учитывать варианты округления и связанные с ним ошибки.

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


Видите разницу в единицу? Попробуем добавить в корзину максимальное количество товара, доступное на складе, и посмотрим, что изменится в каталоге.

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

Теперь, увидев общую картину, можно сказать, что блокировка товара для покупки происходила на моменте добавления товара в корзину, а не при непосредственном оформлении заказа. В результате, просто откладывая товары в корзину, можно заблокировать их для покупки другими пользователями. И доступным для других пользователей он становился только после того, как его удаляли из корзины. Вот так, ошибка в логике работы интернет-магазина могла привести к потерям со стороны его владельца. К счастью, приложение было протестировано еще до выхода его в продуктивное использование, поэтому негативных последствий как для покупателей, так и для продавцов удалось избежать.
Казнить, нельзя помиловать
Несмотря на то, что уязвимости бизнес-логики не входят в список наиболее распространенных уязвимостей, оставлять без внимания их нельзя. Иногда, обнаружив одну подобную уязвимость, ее можно принять за единичную ошибку человека. Но подробный анализ причин ее появления способен помочь улучшить процессы разработки и не допускать подобных ошибок в будущем.
Как говорится, проблему легче предотвратить, чем потом исправлять. Поэтому при разработке приложения стоит избегать неявных предположений о действиях пользователях, тщательно прорабатывать все возможные варианты взаимодействия с системой и обращать внимание на предметную область. И, главное — автоматизированные сканеры тут не помощники. Только ручной анализ функциональности, только хардкор!
Автор: Ольга Рыбакова, аналитик отдела анализа защищенности Solar JSOC
Business Logic Errors
Introduction
Business Logic Errors are ways of using the legitimate processing flow of an application in a way that results in a negative consequence to the organization.
Where to find
This vulnerability can appear in all features of the application.
How to exploit
-
Review Functionality
- Some applications have an option where verified reviews are marked with some tick or it’s mentioned. Try to see if you can post a review as a Verified Reviewer without purchasing that product.
- Some app provides you with an option to provide a rating on a scale of 1 to 5, try to go beyond/below the scale-like provide 0 or 6 or -ve.
- Try to see if the same user can post multiple ratings for a product. This is an interesting endpoint to check for Race Conditions.
- Try to see if the file upload field is allowing any exts, it’s often observed that the devs miss out on implementing protections on such endpoints.
- Try to post reviews like some other users.
- Try performing CSRF on this functionality, often is not protected by tokens
-
Coupon Code Functionality
- Apply the same code more than once to see if the coupon code is reusable.
- If the coupon code is uniquely usable, try testing for Race Condition on this function by using the same code for two accounts at a parallel time.
- Try Mass Assignment or HTTP Parameter Pollution to see if you can add multiple coupon codes while the application only accepts one code from the Client Side.
- Try performing attacks that are caused by missing input sanitization such as XSS, SQLi, etc. on this field
- Try adding discount codes on the products which are not covered under discounted items by tampering with the request on the server-side.
-
Delivery Charges Abuse
- Try tampering with the delivery charge rates to -ve values to see if the final amount can be reduced.
- Try checking for the free delivery by tampering with the params.
-
Currency Arbitrage
- Pay in 1 currency say USD and try to get a refund in EUR. Due to the diff in conversion rates, it might be possible to gain more amount.
-
Premium Feature Abuse
- Try forcefully browsing the areas or some particular endpoints which come under premium accounts.
- Pay for a premium feature and cancel your subscription. If you get a refund but the feature is still usable, it’s a monetary impact issue.
- Some applications use true-false request/response values to validate if a user is having access to premium features or not.
- Try using Burp’s Match & Replace to see if you can replace these values whenever you browse the app & access the premium features.
- Always check cookies or local storage to see if any variable is checking if the user should have access to premium features or not.
-
Refund Feature Abuse
- Purchase a product (usually some subscription) and ask for a refund to see if the feature is still accessible.
- Try for currency arbitrage explained yesterday.
- Try making multiple requests for subscription cancellation (race conditions) to see if you can get multiple refunds.
-
Cart/Wishlist Abuse
- Add a product in negative quantity with other products in positive quantity to balance the amount.
- Add a product in more than the available quantity.
- Try to see when you add a product to your wishlist and move it to a cart if it is possible to move it to some other user’s cart or delete it from there.
-
Thread Comment Functionality
- Unlimited Comments on a thread
- Suppose a user can comment only once, try race conditions here to see if multiple comments are possible.
- Suppose there is an option: comment by the verified user (or some privileged user) try to tamper with various parameters in order to see if you can do this activity.
- Try posting comments impersonating some other users.
-
Parameter Tampering
- Tamper Payment or Critical Fields to manipulate their values
- Add multiple fields or unexpected fields by abusing HTTP Parameter Pollution & Mass Assignment
- Response Manipulation to bypass certain restrictions such as 2FA Bypass
References
- @harshbothra_
Business Logic Errors
Introduction
Business Logic Errors are ways of using the legitimate processing flow of an application in a way that results in a negative consequence to the organization.
Where to find
This vulnerability can appear in all features of the application.
How to exploit
-
Review Functionality
- Some applications have an option where verified reviews are marked with some tick or it’s mentioned. Try to see if you can post a review as a Verified Reviewer without purchasing that product.
- Some app provides you with an option to provide a rating on a scale of 1 to 5, try to go beyond/below the scale-like provide 0 or 6 or -ve.
- Try to see if the same user can post multiple ratings for a product. This is an interesting endpoint to check for Race Conditions.
- Try to see if the file upload field is allowing any exts, it’s often observed that the devs miss out on implementing protections on such endpoints.
- Try to post reviews like some other users.
- Try performing CSRF on this functionality, often is not protected by tokens
-
Coupon Code Functionality
- Apply the same code more than once to see if the coupon code is reusable.
- If the coupon code is uniquely usable, try testing for Race Condition on this function by using the same code for two accounts at a parallel time.
- Try Mass Assignment or HTTP Parameter Pollution to see if you can add multiple coupon codes while the application only accepts one code from the Client Side.
- Try performing attacks that are caused by missing input sanitization such as XSS, SQLi, etc. on this field
- Try adding discount codes on the products which are not covered under discounted items by tampering with the request on the server-side.
-
Delivery Charges Abuse
- Try tampering with the delivery charge rates to -ve values to see if the final amount can be reduced.
- Try checking for the free delivery by tampering with the params.
-
Currency Arbitrage
- Pay in 1 currency say USD and try to get a refund in EUR. Due to the diff in conversion rates, it might be possible to gain more amount.
-
Premium Feature Abuse
- Try forcefully browsing the areas or some particular endpoints which come under premium accounts.
- Pay for a premium feature and cancel your subscription. If you get a refund but the feature is still usable, it’s a monetary impact issue.
- Some applications use true-false request/response values to validate if a user is having access to premium features or not.
- Try using Burp’s Match & Replace to see if you can replace these values whenever you browse the app & access the premium features.
- Always check cookies or local storage to see if any variable is checking if the user should have access to premium features or not.
-
Refund Feature Abuse
- Purchase a product (usually some subscription) and ask for a refund to see if the feature is still accessible.
- Try for currency arbitrage explained yesterday.
- Try making multiple requests for subscription cancellation (race conditions) to see if you can get multiple refunds.
-
Cart/Wishlist Abuse
- Add a product in negative quantity with other products in positive quantity to balance the amount.
- Add a product in more than the available quantity.
- Try to see when you add a product to your wishlist and move it to a cart if it is possible to move it to some other user’s cart or delete it from there.
-
Thread Comment Functionality
- Unlimited Comments on a thread
- Suppose a user can comment only once, try race conditions here to see if multiple comments are possible.
- Suppose there is an option: comment by the verified user (or some privileged user) try to tamper with various parameters in order to see if you can do this activity.
- Try posting comments impersonating some other users.
-
Parameter Tampering
- Tamper Payment or Critical Fields to manipulate their values
- Add multiple fields or unexpected fields by abusing HTTP Parameter Pollution & Mass Assignment
- Response Manipulation to bypass certain restrictions such as 2FA Bypass
References
- @harshbothra_
В случае возникновения ошибки при интеграции извещения с текстом
Ошибка бизнес логики: По лоту с guid = 5d2c3a06-5ec3-e470-e126-7d63091c205f: В соответствии с пунктом 18 постановления правительства Российской Федерации
от 11.12.2014 № 1352 «Об особенностях участия субъектов малого и среднего предпринимательства в закупках товаров, работ, услуг отдельными видами юридических лиц» в
случае, если начальная (максимальная) цена договора (цена) лота на поставку товаров, выполнение работ, оказание услуг не превышает 200 миллионов рублей и указанные товары,
работы, услуги включены в перечень, заказчик обязан осуществить закупки таких товаров, работ, услуг у субъектов малого и среднего предпринимательства.
Заказчик: МУНИЦИПАЛЬНОЕ АВТОНОМНОЕ ДОШКОЛЬНОЕ ОБРАЗОВАТЕЛЬНОЕ УЧРЕЖДЕНИЕ ЦЕНТР РАЗВИТИЯ РЕБЕНКА - ДЕТСКИЙ САД № 82 "СКАЗКА" МУНИЦИПАЛЬНОГО ОБРАЗОВАНИЯ ГОРОД НОВОРОССИЙСК. Коды по ОКПД2: 10.32.19.112.
Необходимо сравнить количество позиций ТРУ и количество заказчиков при просомтре Извещения о проведении процедуры.
Кол-во ТРУ должно быть не меньше, чем кол-во заказчиков.
Начинающие тестировщики могут путать эти параметры, но у них есть существенные отличия. Давайте разберемся в этом подробней.
Для начала рассмотрим каждый атрибут в отдельности.
Серьезность
Серьезность (Severity) — это атрибут, характеризующий влияние дефекта на работоспособность приложения. Проставляется специалистом по тестированию.
Серьезность имеет несколько параметров в зависимости от типа дефекта. Ее степень зависит от того, как она влияет на бизнес-логику (реализацию правил программы).
- S1 – Блокирующая (Blocker). Блокирующая ошибка, приводящая приложение в нерабочее состояние, в результате которого дальнейшая работа с тестируемой системой или ее функциями становится невозможна.
- S2 – Критическая (Critical). Критическая ошибка, неправильно работающая бизнес-логика, проблема, приводящая в нерабочее состояние некоторую часть системы, но есть возможность для работы с тестируемой функцией, используя другие входные точки.
- S3 – Значительная (Major). Значительная ошибка, часть бизнес-логики работает некорректно. Ошибка не критична или есть возможность для работы с тестируемой функцией, используя другие входные точки.
- S4 – Незначительная (Minor). Незначительная ошибка, не нарушающая бизнес-логику тестируемой части приложения, очевидная проблема пользовательского интерфейса.
- S5 – Тривиальная (Trivial). Тривиальная ошибка, не касающаяся бизнес-логики приложения, плохо воспроизводимая проблема, малозаметная по средствам пользовательского интерфейса, проблема сторонних библиотек или сервисов, проблема, не оказывающая никакого влияния на общее качество продукта.
Из описания видно, что с помощью Серьезности мы указываем как найденная ошибка влияет на тестируемое приложение. Если из-за ошибки приложение полностью не работает, то Серьезность высокая. Если найденный дефект мало влияет на функционал и больше относится к визуальной части (например, опечатка в слове), то Серьезность низкая.
Давайте рассмотрим несколько примеров проблем и попробуем правильно определить их Серьезность. Чтобы было понятно, представим, что мы тестируем приложение по заказу такси.
1.Приложение «падает» при попытке найти свободное такси.
Чтобы правильно поставить Серьезность, необходимо определить влияние ошибки на дальнейшую работу функционала. Из названия видно, что после появления ошибки приложение перестает работать. Значит, влияние высокое.
Сразу же отбрасываем Тривиальную и Незначительную Серьезность, так как из их описания понятно, что ошибка не должна сильно влиять на приложение.
У нас остается только три варианта: Значительная, Критическая и Блокирующая серьезности.
Подходит ли нам Значительная Серьезность? Очевидно, что нет. Во-первых, ошибка достаточно критична. Во-вторых, другим способом найти такси мы не можем, т.е. нет возможности работы с тестируемой функцией, используя другие входные точки. Более того, функционал работает не некорректно, а не работает вообще.
Остаются Критическая и Блокирующая серьезности. В нашем случае Блокирующая подходит больше, так как часть функционала не работает и нет других возможностей найти такси. Следовательно, мы выставляем Блокирующую Серьезность.
2. Невозможно указать адрес назначения с помощью “Указать на карте”.
Снова начинаем рассуждать. Тривиальная и Незначительная не подходят, потому что ошибка в какой-то мере нарушают бизнес логику работы приложения. Блокирующую можно не брать, т.к. функционал в целом работает и его можно использовать через другую точку входа, а именно ввести адрес вручную. Остается только два варианта: Критическая и Значительная. Мы уже сказали, что проблема не приводит к полной неработоспособности части функционала. Тем не менее это значительная ошибка, т.к. функционал частично не работает, следовательно остается только вариант Значительная. Его мы и укажем.
Как вы могли понять, Серьезность относится к технической части приложения и указывает на то, как сильно ошибка влияет на работоспособность приложения.
Приоритет
Приоритет отличается от Серьезности тем, что указывает когда необходимо исправить ошибку.
Приоритет (Priority) – это атрибут, указывающий на очередность выполнения задачи или устранения дефекта. Проставляется руководителем или менеджером проекта.
- P1 – Высокий (High) – требуется исправить в первую очередь.
- P2 – Средний (Medium) – требуется исправить во вторую очередь, когда нет дефектов с высоким приоритетом.
- P3 – Низкий (Low) – исправляется в последнюю очередь, когда все дефекты с более высоким приоритетом уже исправлены.
С помощью приоритета менеджер проекта говорит, когда стоит исправить найденную проблему.
На первый взгляд можно подумать, что Приоритет и Серьезность одинаковы, ведь чем серьезней ошибка, тем быстрее её нужно исправить. Но, если глубже рассмотреть эти атрибуты, то можно найти различия.
Например, мы нашли опечатку в слове. Из названия видно, что это ошибка с Незначительной серьезностью и, вроде бы, ее не стоит исправлять в приоритете. Но если это слово находится на главном экране и является частью названия приложения, то, очевидно, что ее необходимо исправить как можно раньше.
Приоритет определяется исходя из масштабности проблем для пользователей и продукта. Для понимая можно использовать матрицу:

Теперь, когда мы разобрались что означает каждый атрибут, давайте посмотрим в чем их различие:

________________________________
Если остались вопросы по определению параметров Серьезность и Приоритет, то задавайте их в комментариях к статье.
________________________________
Предыдущие статьи по оформлению баг-репорта:
Назначение отчета https://sedtest-school.ru/testovaya-dokumentacziya/otchety-o-defektah-naznachenie/
Шаблон отчета об ошибке https://sedtest-school.ru/testovaya-dokumentacziya/otchety-o-defektah-shablon-otcheta-ob-oshibke/
Я нахожусь на перепутье с некоторым дизайном API для клиента (JS в браузере), чтобы общаться с сервером. Мы используем HTTP 409 Conflict для представления сбоя действия из-за действующей блокировки безопасности. Замок Satefy предотвращает случайное внесение разработчиками изменений в производственные системы наших клиентов. Мне было поручено немного более изящно обрабатывать 409-е на клиенте, чтобы указать, почему не удался конкретный вызов API.
Мое решение состояло в том, чтобы обернуть обработчики сбоев любого из наших вызовов AJAX, которые будут отображать уведомление на клиенте, когда что-то выходит из строя из-за 409 — это все хорошо и работает хорошо наряду с другими ошибками 4XX и 5XX, которые используют тот же механизм.
Возникла проблема, когда один из наших обработчиков маршрутов отвечает 409 при обнаружении ошибки бизнес-логики — моя оболочка AJAX сообщает, что включена защитная блокировка, в то время как существующий обработчик ошибок клиента сообщает, что (по его мнению) проблема основана на теле ответа. Простым решением было бы изменить либо ответ обработчика, либо код состояния, который мы используем для представления замка безопасности.
Что подводит меня к перекрестку: следует ли использовать коды состояния HTTP даже для представления ошибок бизнес-логики? Этот вопрос решает ту же проблему, с которой я сталкиваюсь, но он не получил большой тяги. Как указано в связанном ответе, я склоняюсь к использованию HTTP 200 OK с соответствующим телом для представления ошибок в бизнес-логике.
У кого-нибудь есть здесь сильные мнения? Кто-нибудь может убедить меня, что это неправильный способ представлять неудачу?
Ответы:
Кейси раскрывает главное.
Ключевая идея в любом веб-API: вы адаптируете свой домен, чтобы он выглядел как хранилище документов. GET / PUT / POST / DELETE и так далее — все это способы взаимодействия с хранилищем документов.
Так в способе мышления о том , что коды использования, чтобы понять , что аналогичная операция в документе магазине, и что эта неудача будет выглядеть в этом аналоге.
2xx совершенно не подходит
Класс статуса 2xx (Успешный) указывает, что запрос клиента был успешно получен, понят и принят.
5xx тоже не подходит
Класс кода состояния 5xx (Ошибка сервера) указывает, что сервер знает, что он допустил ошибку
В этом случае сервер не ошибся; он знает, что вы не должны изменять этот ресурс в это время.
Ошибки бизнес-логики (это означает, что бизнес-инвариант не позволяет предлагаемое редактирование в настоящее время), вероятно, 409
Код состояния 409 (Конфликт) указывает, что запрос не может быть выполнен из-за конфликта с текущим состоянием целевого ресурса. Этот код используется в ситуациях, когда пользователь может разрешить конфликт и повторно отправить запрос. Сервер ДОЛЖЕН генерировать полезную нагрузку, которая включает в себя достаточно информации, чтобы пользователь мог распознать источник конфликта.
Обратите внимание на этот последний бит — полезная нагрузка ответа 409 должна сообщать потребителю информацию о том, что пошло не так, и в идеале должна включать средства управления гипермедиа, которые приводят потребителя к ресурсам, которые могут помочь разрешить конфликт.
Мое решение состояло в том, чтобы обернуть обработчики сбоев любого из наших вызовов AJAX, которые будут отображать уведомление на клиенте, когда что-то выходит из строя из-за 409 — это все хорошо и работает хорошо наряду с другими ошибками 4XX и 5XX, которые используют тот же механизм.
И я бы указал на это как на проблему; Ваша реализация на клиенте предполагала, что кода состояния было достаточно для определения проблемы. Вместо этого ваш клиентский код должен проверять полезную нагрузку и действовать на основе доступной там информации.
То есть, в конце концов, как это сделает хранилище документов?
409 Conflict
your proposed change has been declined because ${REASON}.
The following resolution protocols are available: ${LINKS[@]})
Тот же подход с a 400 Bad Requestтакже будет приемлемым; что примерно «переводит на» возникла проблема с вашим запросом. Мы не можем быть обеспокоены, чтобы выяснить, какой код статуса подходит лучше всего, так что вот и все. Смотрите полезную нагрузку для деталей. «
Я бы использовал 422. Ввод действителен, поэтому 400 не правильный код ошибки для использования
Спецификация WebDAV включает эту рекомендацию
Код состояния 422 (Unprocessable Entity) означает, что сервер понимает тип содержимого объекта запроса (следовательно, код состояния 415 (Unsupported Media Type) является неподходящим), и синтаксис объекта запроса является правильным (таким образом, 400 (неверный запрос) ) код состояния не подходит), но не удалось обработать содержащиеся в нем инструкции. Например, это условие ошибки может возникать, если тело запроса XML содержит правильно сформированные (то есть синтаксически правильные), но семантически ошибочные инструкции XML.
Я не верю, что это вполне совпадает (хотя я согласен, что 400в качестве альтернативы это вызывает некоторые сомнения ). Моя интерпретация 422означает, что «вы отправили неправильную сущность», где 409«вы отправили сущность в неправильное время».
Другими словами, 422указывает на проблему с сообщением запроса, рассматриваемым изолированно, где 409указывается, что сообщение запроса конфликтует с текущим состоянием ресурса.
Обсуждение Беном Надалем 422 может быть полезным для рассмотрения.
По моему опыту, кодов ошибок HTTP недостаточно для представления ошибок бизнеса. Однако они полезны для представления классов ошибок.
Поэтому я рекомендую использовать коды ошибок HTTP для категорий ошибок, но выбрать конкретную ошибку для сбоев бизнес-логики (например, 409 Conflict … 200 OK будет вводить в заблуждение здесь) и включить в ответ данные, указывающие на конкретную бизнес-ошибку , Убедитесь, что это часть содержимого ответа, а не текста статуса, поскольку некоторые браузеры игнорируют пользовательский текст статуса. Язык, который я люблю использовать, имеет типы объединения, которые удобны для представления сообщений. Но вы также можете определить строковые константы для случаев ошибки.
Примеры
// error with text response
409 Conflict "safety_lock_engaged"
409 Conflict "customer_not_eligible_for_selected_discount"
// warning with JSON response
202 Accepted { "backorderedProductIds": [ 37, 476 ] }
Как правило, я бы не использовал коды состояния HTTP для представления конкретных ошибок бизнес-логики. Это потому, что они уже имеют семантическое значение, которое определяется мировым стандартом. Другие системы, новые разработчики и т. Д. Будут сбиты с толку вашим отклонением от стандарта.
В недавнем подобном исследовании я обнаружил, что общепринятым является использование 400 Bad Requestв случае ошибок валидации и тому подобное. Таким образом, вы используете один код состояния для всех ошибок бизнес-логики.
Кстати, его 409следует использовать, когда ресурс изменился, когда вы редактировали его и пытались сохранить его снова.
Вы можете использовать «Неверный запрос» и включить идентификатор нарушенного бизнес-правила, а также некоторые подробности в теле ответа.
![]()
Сообщение от sau

Что касается контроллеров , то да , его задача принять данные запроса и передать дальше по цепочке
Т.е. они ничего не делают?
У меня сейчас в одном из проектов разделение сделано именно согласно здравому смыслу, т.е. контроллер отвечает исключительно за получение запроса и возврат результата. Вся БЛ вынесена в сервисы. И получается, что все контроллеры выглядят так:
| C# | ||
|
При этом сервисы БЛ нигде не переиспользуются и вряд ли будут переиспользоваться, а все внешние клиенты, которым нужен определённый функционал, идут именно через API, т.е. проходят через контроллеры.
И вот, видя всю эту толпу пустых контроллеров, а так же сервисов БЛ, которые один-в-один мапятся на эти контроллеры и нужны только для них, невольно возникает мысль избавиться от избыточных файлов/сборок и перенести всю БЛ в контроллеры. А потом, если вдруг возникнет-таки внезапная потребность реиспользовать какую-то часть БЛ, выносить конкретную часть в сервисы по мере необходимости.
Добавлено через 17 минут
Изначально там ещё была реализована идея, что внешний API никак не должен быть завязан на те структуры данных, которыми оперируют внутренние сервисы, а сервисы ничего не должны знать про внешние контракты конкретных API. Это привело к разделению DTO на те, которые принимаются контроллером и те, которые используются сервисами. И метод контроллера занимался перекладыванием одних DTO в другигие перед и после вызова метода сервиса. Перекладывал один-в-один. Можно было, конечно, поискать какое-нибудь решение для упрощения процедуры мапинга однотипных объектов, но по факту было принято решение для API-методов использовать те же DTO, которыми оперируют сервисы.
{«id»:13812,»url»:»/distributions/13812/click?bit=1&hash=7aad8372ebaeed8b9f0411b6538b74104d083797cee812ade3ece5f97be0c878″,»title»:»u0427u0435u043a-u043bu0438u0441u0442 u0434u043bu044f u0431u0438u0437u043du0435u0441u0430: u043du0443u0436u043du044b u043bu0438 u0432u0430u043c API?»,»buttonText»:»u041fu0440u043eu0432u0435u0440u0438u0442u044c»,»imageUuid»:»f6c199c9-f72d-52bc-a539-75fc9e2f6f21″,»isPaidAndBannersEnabled»:false}
Бизнес-логика приложения – это, по сути, описание схем, по которым приложение взаимодействует с пользователем. Когда пользователь оформляет подписку, или заполняет форму заказа, или просто авторизуется – все эти действия обрабатываются «под капотом» приложения в определенном порядке.
Какие данные нужно запросить? Соответствуют ли введенные данные заданному формату? Что произойдет после того, как пользователь нажмет кнопку «Подтвердить»? А есть ли вообще у него права доступа к данной операции? На все эти и многие другие вопросы можно ответить, изучив, как построена бизнес-логика конкретного приложения.
Простейший пример: администратор авиакомпании (пользователь) регистрирует пассажира на рейс (вносит информацию в базу данных).
Что делает пользователь:
1.Открывает информацию о выбранном рейсе, переходит к списку уже зарегистрированных пассажиров, нажимает «Зарегистрировать пассажира».
2.Заполняет форму регистрации: вводит номер рейса, выбирает пассажира, указывает место и статус регистрации.
3.Нажимает кнопку «Подтвердить»
4.Видит нового пассажира в общем списке.
Как это выглядит с точки зрения бизнес-логики приложения:
1.Приложение проверяет, авторизован ли пользователь и имеет ли права доступа к выбранной странице, а также операции регистрации.
2.Ждет, пока пользователь заполнит форму.
3.Обрабатывает введенные данные:
a. Проверяет, соответствуют ли введенные данные требованиям приложения (эти требования заранее прописаны программистом): например, в поле «Номер рейса» должно быть целое число.
b. Получает из базы данных информацию: например, о рейсе и связанных с ним регистрациях (чтобы внести изменения), пассажире (чтобы проверить, действительно ли этот пассажир есть в базе данных).
c. Выдает сообщения об ошибках, если поля заполнены неверно.
d. Отправляет информацию в базу данных, отдавая команды на создание в ней новых записей или обновлении существующих.
4.Выводит обновленную информацию на экран.
Общая логика приложения строится из бизнес-процессов – схем, описывающих конкретные операции в системе: создание записи о пассажире, добавление в систему нового рейса, редактирование информации о регистрации.
Когда речь идет о классическом программировании, то для описания всех процессов используются блоки кода. Многие из них пишутся по шаблонам – просто используются в разной последовательности и для работы с разными данными.
Именно благодаря этой «шаблонности» в no-code разработке появилась возможность использовать инструменты визуального программирования – так называемые дизайнеры бизнес-логики. Они помогают выбрать нужные блоки, скомпоновать в нужной последовательности, настроить. И даже создать некоторые блоки автоматически, в зависимости от настроек других компонентов приложения. Итог – готовая бизнес-логика без необходимости проводить многие часы над строками кода.