Как не сломать доступы при добавлении новой функции
Практическое руководство для команд, которые хотят выпускать фичи быстро и не платить за это безопасностью
Введение: почему доступы ломаются именно при добавлении новых фич
Разработчик добавляет новый API-эндпоинт. Функция работает корректно — данные приходят, бизнес-логика выполняется, тесты зелёные. PR проходит ревью. Через неделю на пентесте или в bug bounty оказывается, что эндпоинт доступен без авторизации, или что обычный пользователь может вызвать его с чужим user_id, или что роль viewer может делать мутации.
Это не редкость. По данным OWASP, нарушения контроля доступа фиксируются буквально в каждом приложении, которое проходит профессиональное тестирование [1]. Среднее количество инцидентов по этой категории в 2025 году — 3,74% от всех эндпоинтов, а суммарное количество зафиксированных случаев превышает 1,8 миллиона [1][8].
Механика почти всегда одинакова: доступы не «взламывают» в кинематографическом смысле — их просто не добавляют [5][9]. Новая функция появляется в продакшне раньше, чем кто-то успевает спросить: «А кому вообще разрешено это делать?»
Эта статья — практическое руководство для Tech Lead, разработчика и AppSec-специалиста о том, как выстроить процесс, при котором авторизация новых функций проверяется до merge и до релиза, а не после инцидента.
Часть 1. Что именно ломается и почему
Аутентификация vs авторизация: разница, которую часто не замечают
Аутентификация отвечает на вопрос «кто ты?» — токен, пароль, биометрия, сессия. Авторизация отвечает на вопрос «что тебе разрешено?» — роль, атрибуты, политики, контекст [2].
На практике команды хорошо выстраивают аутентификацию: JWT, OAuth 2.0, MFA — всё это внедрено, документировано и проверяется в тестах. Авторизация уходит на второй план. Разработчик видит, что пользователь аутентифицирован, и подсознательно считает, что этого достаточно. Ворота в здание проверяются; двери внутри — нет [7].
Типовые точки отказа при разработке новых функций
Когда команда добавляет новую фичу, доступы ломаются в нескольких типовых сценариях.
Первый — новый эндпоинт без проверки роли. Разработчик создаёт POST /api/v1/reports/export, подключает middleware аутентификации, но забывает добавить проверку роли. Эндпоинт доступен любому аутентифицированному пользователю, включая viewer [6].
Второй — IDOR (Insecure Direct Object Reference). Эндпоинт принимает ?account_id=12345 и возвращает данные без проверки, что этот аккаунт принадлежит текущему пользователю. Атакующий перебирает идентификаторы и получает чужие данные. Именно через IDOR в 2023 году утекли данные почти 10 миллионов клиентов Optus [7].
Третий — вертикальная эскалация привилегий. Рефакторинг старого middleware или изменение структуры ролей ломает существующую логику. Пользователь manager получает доступ к функциям admin — или наоборот, admin теряет часть доступов при деплое.
Четвёртый — авторизация только на уровне UI. Кнопка «Удалить» спрятана для роли viewer, но DELETE /api/v1/resource/:id вызвать напрямую никто не мешает [14]. Браузер не является слоем защиты.
Пятый — авторизация в frontend-компонентах (актуально для Server Actions в Next.js и аналогов). Каждый Server Action должен быть самодостаточным с точки зрения безопасности — не полагаться на то, что его вызовут из «правильного» места [20]. Изменение флоу или маршрута может оставить Action открытым.
Шестой — CORS, настроенный слишком широко. При добавлении нового публичного эндпоинта разработчик ставит Access-Control-Allow-Origin: * для удобства отладки, и это уходит в продакшн [17].
Часть 2. Модели авторизации: RBAC, ABAC, ReBAC
Выбор модели — это не техническая деталь
OWASP Authorization Cheat Sheet прямо указывает: решение о модели авторизации должно приниматься на этапе проектирования, до написания кода. От него зависит весь SDLC [10].
Распространённая ошибка — начать с простых if user.role == 'admin' внутри бизнес-логики, а потом масштабировать это вручную. Когда ролей становится 10, а правил — 50, код превращается в нечитаемый лабиринт условий. При добавлении новой функции разработчик не понимает, какую ветку добавить, и добавляет неправильную — или не добавляет никакой.
RBAC: просто, предсказуемо, но масштабируется плохо
Role-Based Access Control привязывает разрешения к ролям: admin, editor, viewer. Понятна, легко объясняется команде, хорошо работает для простых иерархий.
Проблема — «взрыв ролей» (role explosion). Когда бизнес требует «менеджер проекта A может редактировать, менеджер проекта B — только просматривать», роли начинают размножаться: project_a_manager, project_b_manager. При добавлении новой функции разработчик должен явно обновить каждую роль. Пропуск одной — регрессия [18].
ABAC: гибко, но сложнее тестировать
Attribute-Based Access Control принимает решение о доступе на основе атрибутов пользователя, ресурса и контекста: время суток, геолокация, уровень чувствительности данных. Модель мощная, но трудно поддаётся ручному ревью — цепочки условий неочевидны [13].
При добавлении новой функции нужно явно описать, какие атрибуты влияют на доступ к ней. Если это не задокументировано в политике, атрибут может не проверяться вовсе.
ReBAC: для сложных граф-структур
Relationship-Based Access Control (модель Google Zanzibar, реализации OpenFGA, SpiceDB) строит авторизацию на основе отношений между объектами: «пользователь является участником команды, которая имеет доступ к документу». Решает проблемы RBAC в задачах collaborative permissions, но требует более сложной инфраструктуры [20].
OpenFGA в октябре 2025 года перешёл в статус CNCF Incubating project, что означает зрелость для продакшн-использования [12][20].
Декларативные политики — лучше, чем if-условия в коде
Общий тренд 2024–2026 годов: выделять авторизационную логику в отдельный слой — политику. Инструменты вроде Cerbos, Oso, Cedar, Casbin позволяют описывать правила декларативно, версионировать их как код и тестировать независимо от бизнес-логики [18]. При добавлении новой функции разработчик добавляет правило в политику — и оно автоматически применяется ко всем проверяющим точкам. Этот подход называется Policy-Based Access Control (PBAC) [18].
Часть 3. Deny-by-default и серверная проверка
Принцип, без которого всё остальное не работает
OWASP формулирует это однозначно: кроме публичных ресурсов, доступ запрещён по умолчанию [17]. Если разработчик не добавил явное разрешение — ресурс недоступен. Это контрастирует с практикой «открыть по умолчанию, закрыть потом» — при которой новая функция публично доступна до момента, когда кто-то вспомнит добавить ограничение.
На практике это означает несколько вещей.
Middleware авторизации должен быть включён глобально. Отдельные маршруты явно помечаются как публичные, а не наоборот. Иначе разработчик, который добавляет новый роутер, по умолчанию делает его открытым [13].
Проверка должна происходить на сервере. UI-элементы (скрытые кнопки, отключённые поля) — вспомогательная мера, а не защита [14][11]. Атакующий вызывает API напрямую, минуя интерфейс.
Авторизация должна проверяться в каждой операции, а не только при входе. Аутентификация токена при логине не даёт автоматического разрешения на каждый последующий запрос — особенно при работе с чужими объектами [16].
Часть 4. Авторизация как часть разработки: как встроить в процесс
Требования на этапе проектирования
Прежде чем написать первую строчку кода для новой функции, команда должна ответить на три вопроса:
- Кто может вызывать эту функцию? (роль, атрибут, отношение)
- Владение: может ли пользователь действовать только со своими объектами или с чужими тоже?
- Что произойдёт, если проверка не пройдена? (403 Forbidden, редирект, лог-событие)
Эти ответы должны стать частью задачи или спецификации. Если их нет — задача не готова к разработке.
Тесты авторизации как первичные граждане
OWASP Web Security Testing Guide указывает: проверки авторизации должны быть частью юнит- и интеграционных тестов наравне с функциональными [4].
Минимальный набор тестов для каждого нового эндпоинта:
- Запрос без токена — ожидаем 401.
- Запрос с токеном пользователя, у которого нет нужной роли — ожидаем 403.
- Запрос с корректной ролью, но чужим
resource_id— ожидаем 403 (IDOR-проверка). - Запрос с корректной ролью и своим
resource_id— ожидаем 200.
Эти тесты должны быть автоматическими и запускаться в CI на каждый PR. Ручное QA не заменяет автоматику — ревьюер пропустит, QA-инженер не проверит все роли.
Code review: что смотреть в новом PR
При ревью PR с новыми API-эндпоинтами или изменением логики доступа стоит проверять несколько вещей.
Есть ли явная проверка авторизации на каждом новом эндпоинте? Если middleware стоит глобально — убедиться, что новый роутер его не обходит.
Есть ли проверка владения объектом, а не только проверка роли? Роль editor позволяет редактировать документы — но только свои или чужие тоже?
Используется ли параметр из запроса (URL, body) без верификации? ?user_id=123 — это классический IDOR, если сервер не сравнивает с current_user.id [17].
Изменяет ли PR существующие роли или политики? Рефакторинг роли может сломать права в других частях системы.
Добавлены ли тесты для «негативных» сценариев — что запрещено, а не только что разрешено?
CORS и конфигурация
При добавлении публичных или cross-origin эндпоинтов CORS должен быть настроен явно: конкретные домены, а не *. OWASP отмечает misconfiguration CORS как одну из типовых форм Broken Access Control [17]. Открытый CORS позволяет атакующему делать запросы от имени аутентифицированного пользователя с произвольного домена.
Часть 5. Zero Trust и принцип минимальных привилегий
Почему «доверяй внутренней сети» больше не работает
NIST SP 800-207 фиксирует: Zero Trust Architecture исходит из того, что нет неявного доверия ни к пользователям, ни к устройствам, ни к сервисам — только потому что они находятся «внутри» сети [15]. Каждый запрос аутентифицируется и авторизуется независимо.
Для разработки это означает: внутренний микросервис не должен получать автоматический доступ к данным другого микросервиса только потому, что они «в одной сети». Каждый вызов требует авторизации.
При добавлении нового сервиса или функции команда определяет минимально необходимые разрешения (Principle of Least Privilege) — и выдаёт только их [15]. Разрешения не накапливаются по умолчанию; они явно назначаются для конкретной операции.
Практика PoLP при разработке новых функций
Принцип минимальных привилегий применяется не только к пользователям, но и к сервисным аккаунтам, API-ключам, CI/CD-агентам и machine identities [15].
Типовая ошибка: для нового сервиса создаётся один «удобный» service account с широкими правами — чтобы не возиться с гранулярной настройкой. В итоге компрометация одного компонента даёт атакующему доступ ко всему, что доступно этому аккаунту. В 2024 году инцидент с Amazon ECS показал, как злоупотребление IAM-ролями с избыточными правами позволило атакующему эскалировать привилегии в облачной инфраструктуре [19].
Часть 6. Чек-лист: что проверять до merge и до релиза
До написания кода
- Авторизационные требования описаны в задаче: кто может, кто не может, что происходит при отказе.
- Определена модель: RBAC/ABAC/ReBAC, политика описана или обновлена.
- Рассмотрен вопрос владения объектами: нужна ли проверка
owner_id == current_user.id.
В коде
- Каждый новый эндпоинт явно проверяет авторизацию на сервере, а не только в UI.
- Нет доверия к параметрам из запроса без верификации (URL-параметры, body, заголовки).
- Централизованный middleware авторизации не обходится; если нужно публичное исключение — оно явно задокументировано.
- CORS настроен для конкретных доменов, а не открыт широко.
- Нет debug-флагов или временных
// TODO: add auth checkв продакшн-ветке.
В тестах
- Тесты покрывают «запрещённые» сценарии: нет токена, не та роль, чужой объект.
- Тесты запускаются в CI на каждый PR.
- При изменении ролей или политик — регрессионные тесты для всех затронутых путей.
В PR-ревью
- Ревьюер явно проверяет авторизацию нового кода — не только бизнес-логику.
- Изменения, затрагивающие модель ролей или middleware, требуют ревью от security-компетентного участника.
Перед релизом
- Если функция добавляет новые API — проведено smoke-тестирование на staging с разными ролями.
- Логирование авторизационных отказов настроено: 403-ответы должны быть видны в мониторинге, а не теряться.
Часть 7. Типичные ошибки и как их избежать
Ошибка 1: «Прячем в UI — значит закрыли»
Скрытые кнопки, disabled-поля, отсутствие ссылки в меню не защищают эндпоинт. Любой инструмент для работы с HTTP (curl, Burp Suite, Postman) позволяет вызвать API напрямую. Проверка авторизации должна быть только серверной [14].
Ошибка 2: Проверяем вход, не проверяем каждую операцию
Пользователь аутентифицировался — это не разрешение на каждый последующий запрос. При операциях с конкретными объектами нужно проверять, что объект принадлежит текущему пользователю или пользователь имеет явное разрешение на него. NIST SP 800-207 фиксирует: «авторизация к одному ресурсу не даёт автоматического доступа к другому» [16].
Ошибка 3: Авторизация разбросана по коду
Когда проверки авторизации встроены в бизнес-логику через if role == 'admin' в десятках мест, добавление новой функции требует обновления каждого места. Что-то неизбежно пропускается. Централизованный слой авторизации (middleware, policy engine) решает эту проблему: новое правило описывается один раз и применяется везде [17].
Ошибка 4: Нет тестов на «что запрещено»
Большинство тестов проверяют happy path — что авторизованный пользователь может делать. Тесты на запрещённые сценарии (неверная роль, чужой объект, отсутствующий токен) часто отсутствуют. Именно они ловят регрессии при рефакторинге [4].
Ошибка 5: Service accounts с широкими правами
Для нового сервиса или CI/CD-агента создаётся сервисный аккаунт с правами admin «для простоты». Принцип минимальных привилегий требует давать только то, что нужно для конкретной операции [15].
Ошибка 6: Feature flags как скрытая авторизация
Feature flag скрывает новую функцию от пользователей в UI. Но если API-эндпоинт уже задеплоен — он доступен независимо от флага. Feature flag не заменяет авторизацию.
Часть 8. Авторизация в AI-кодинге: новые риски
Скорость разработки с AI-ассистентами растёт — и с ней растёт риск появления эндпоинтов, написанных быстро, но без явной авторизационной логики. AI-генерированный код часто реализует функциональность корректно, но опускает security-слой: он не знает, какая роль должна иметь доступ, если это не описано в промпте.
PR, написанный с помощью AI, может содержать полностью рабочий CRUD-эндпоинт без единой строки авторизации. «Работает» не значит «безопасно для merge» — это разные утверждения.
Для команд, которые используют AI-кодинг, важно встроить контроль именно на уровне изменения, а не откладывать его до пентеста или аудита. Инструменты вроде HighVibe анализируют конкретное изменение в PR — код, конфигурацию, служебные файлы — и помогают заметить риск до merge: отсутствующие проверки авторизации, открытый CORS, debug-настройки в production-конфиге. Это не замена SAST/SCA, а дополнительный слой контроля, ориентированный именно на контекст изменения и релиза.
Часть 9. Тренды 2025–2026
Authorization as infrastructure
Выделение авторизации в отдельный слой инфраструктуры — нарастающий тренд. OpenFGA (CNCF Incubating), Cedar (AWS), Cerbos, Oso — инструменты, позволяющие описывать политики декларативно, тестировать их как код и применять единообразно через весь стек [20]. При добавлении новой функции разработчик добавляет правило в политику, а не встраивает условие в код.
AI Agent Authorization
В 2025–2026 годах появилась новая задача: авторизация не только людей, но и AI-агентов. Amazon Bedrock AgentCore Policy, интеграции LangChain с SpiceDB, Oso с функциями risk control для coding agents — индустрия начала решать, что может делать AI-агент от имени пользователя [20]. При разработке функций, которые будут вызываться агентами, авторизационная модель должна учитывать machine identities наравне с человеческими.
Continuous authorization
Вместо одноразовой проверки при входе — постоянная верификация контекста при каждом запросе: поведение пользователя, состояние устройства, аномалии [15]. Это принцип Zero Trust в действии: авторизация не накапливается, а вычисляется в реальном времени.
Заключение: что делать дальше
Broken Access Control остаётся самой распространённой уязвимостью приложений не потому, что её сложно исправить — а потому что её легко не заметить при высоком темпе разработки. Каждый новый эндпоинт, каждый рефакторинг ролей, каждый новый сервис — потенциальная точка регрессии доступов.
Практические следующие шаги для команды:
- Провести аудит существующих эндпоинтов: есть ли на каждом явная проверка авторизации?
- Внедрить deny-by-default в middleware: новые роуты публичны только если явно помечены.
- Добавить в definition of done проверку авторизационных требований до начала разработки.
- Написать автоматические тесты на «запрещённые» сценарии и включить их в CI.
- При использовании AI-кодинга — убедиться, что ревью PR включает явную проверку наличия авторизационной логики.
Быстро выпустить функцию и выпустить её безопасно — не противоречие. Это вопрос встроенного процесса.
Источники
[1] OWASP Foundation — «A01:2025 Broken Access Control» — https://owasp.org/Top10/2025/A01_2025-Broken_Access_Control/
[2] PortSwigger Web Security Academy — «Access control vulnerabilities and privilege escalation» — https://portswigger.net/web-security/access-control
[3] Oso — «RBAC vs ABAC vs PBAC: Understanding Access Control Models in 2025» — https://www.osohq.com/learn/rbac-vs-abac-vs-pbac
[4] OWASP Web Security Testing Guide — «Security Tests Integrated in Development and Testing Workflows» — https://owasp.org/www-project-web-security-testing-guide/latest/2-Introduction/
[5] Parasoft — «OWASP Top 10 2025: What Changed & Why It Matters» — https://www.parasoft.com/blog/owasp-top-10/
[6] Xygeni — «OWASP Top 10 2025 Explained for Developers» — https://xygeni.io/blog/owasp-top-10-2025-explained-for-developers/
[7] IntelligenceX — «Broken Access Control (A01:2025): Complete Guide» — https://blog.intelligencex.org/broken-access-control-owasp-a01-2025-complete-guide
[8] Cerbos — «Broken Access Control Still Tops the List: OWASP Top 10 2025» — https://www.cerbos.dev/blog/broken-access-control-owasp-top-10-2025
[9] BSG Tech — «OWASP Top 10 2025: What Changed and Why It Matters» — https://bsg.tech/blog/owasp-top-10/
[10] OWASP Cheat Sheet Series — «Authorization Cheat Sheet» — https://cheatsheetseries.owasp.org/cheatsheets/Authorization_Cheat_Sheet.html
[11] Authgear — «What is Broken Access Control Vulnerability and How to Prevent It» — https://www.authgear.com/post/what-is-broken-access-control-vulnerability-and-how-to-prevent-it/
[12] DEV Community — «RBAC vs ABAC vs ReBAC: How to Choose and Implement Access Control Models» — https://dev.to/kanywst/rbac-vs-abac-vs-rebac-how-to-choose-and-implement-access-control-models-3i2d
[13] Escape Tech — «Access Control Models: RBAC, ABAC, DAC» — https://escape.tech/blog/access-control-models/
[14] PortSwigger — «Access control vulnerabilities» (Web Security Academy) — https://portswigger.net/web-security/access-control
[15] NIST — «SP 800-207: Zero Trust Architecture» — https://csrc.nist.gov/pubs/sp/800/207/final
[16] CyberArk — «What Is NIST SP 800-207?» — https://www.cyberark.com/what-is/nist-sp-800-207-cybersecurity-framework/
[17] BrightSec — «Broken Access Control: Examples and 4 Defense Tips» — https://brightsec.com/blog/broken-access-control-attack-examples-and-4-defensive-measures/
[18] Securityium — «Mastering Access Control Vulnerabilities and Privilege Escalation» — https://www.securityium.com/mastering-access-control-vulnerabilities-and-privilege-escalation/
[19] Aviatrix — «Amazon ECS 2024 Privilege Escalation Exposes IAM Identity Hijacking» — https://aviatrix.ai/threat-research-center/amazon-ecs-2024-privilege-escalation-iam-hijacking/
[20] Habr / Simbirsoft — «Архитектура безопасности во frontend-приложениях: Server Actions и защита данных в Next.js» — https://habr.com/ru/companies/simbirsoft/articles/1039136/