Аутентификация и авторизация: как тестировщику проверять права доступа
Многие серьёзные security-баги начинаются с простой путаницы: система знает, кто ты, но забывает проверить, принадлежит ли тебе конкретный объект.
- Нет токена: ожидаем 401
- Неверный токен: ожидаем 401
- Правильный пользователь, не та роль: 403 или нет действия
- Правильная роль, чужой объект: 403 или 404
Аутентификация отвечает “кто ты?”
Аутентификация — это вход, пароль, токен, сессия и срок действия. Она подтверждает личность, но не решает, какие данные пользователь может читать или менять.
Базовые проверки: правильные данные, неверный пароль, регистр email, отсутствие токена, истёкший токен и logout.
Авторизация отвечает “что тебе можно?”
Авторизация проверяет роль и владение объектом. Пользователь может быть залогинен и всё равно не иметь права открыть чужой заказ, счёт, документ или карточку клиента.
Здесь часто ломается API: id легко угадать, а скрытая кнопка на фронтенде не защищает backend.
Проверка владения объектом
Создай или найди двух пользователей. Открой объект владельцем, запомни id, затем запроси тот же id токеном второго пользователя. Обычно ожидается 403 или 404.
Почему иногда лучше 404
Для приватных объектов 404 скрывает сам факт существования. 403 говорит, что объект есть, но тебе нельзя. Как правильно — решают требования продукта.
Проверка ролей
Роли нужно проверять и в UI, и в API. Если admin-only кнопка скрыта, всё равно отправь запрос с токеном обычного пользователя.
Скрытая кнопка — это удобство. Отклонённый запрос — это безопасность.
Типичные access-баги
Частые дефекты: нет фильтра по владельцу, роль проверяется только на фронтенде, токен работает после logout, endpoint по-разному отвечает на существующий и несуществующий приватный объект.
В багрепорте про доступ укажи оба аккаунта, контекст токенов и id объекта. Без этого разработчик не воспроизведёт границу прав.
Матрица actor × action × object
Список ролей недостаточен. Построй строки из субъекта, действия и ресурса: manager A читает своего клиента, manager A меняет клиента B, обычный user вызывает admin endpoint, бывший сотрудник использует старый token. Для каждого сочетания нужен expected: allow, deny или скрыть существование.
Проверяй не только GET. BOLA часто закрыта на чтение, но остаётся в PATCH, DELETE, bulk endpoint, export или вложенном object id в JSON. UUID усложняет угадывание, но не заменяет серверную проверку права.
Actor Action Object Expected\nmanager A GET client A 200\nmanager A GET client B 403/404 по контракту\nmanager A PATCH client B 403/404, данные не меняются\nviewer DELETE client A 403\nno token GET client A 401 + WWW-Authenticate
Жизненный цикл сессии и токена
Проверь выдачу, rotation после login или повышения прав, expiry, refresh, logout, отзыв, смену пароля и параллельные устройства. Старый access token иногда живёт до короткого expiry по принятой архитектуре; тогда logout обязан отозвать refresh token и UI не должен обещать больше, чем гарантирует сервер.
- Session id не остаётся тем же до и после login — иначе возможна session fixation.
- Cookie имеет Secure, HttpOnly и подходящий SameSite; token не попадает в URL и логи.
- Истёкший, испорченный и подписанный не тем ключом token отклоняются.
- После смены роли permission обновляется в согласованный срок, а кэш не оставляет старое право.
- Refresh reuse, logout и смена пароля ведут себя по документированной политике.
BOLA, BFLA и доступ к отдельным полям
BOLA — пользователь имеет доступ к функции, но backend не проверяет право на конкретный object id. BFLA — пользователь вызывает функцию не своей роли, например обычный manager открывает admin export. Broken Object Property Level Authorization проявляется, когда разрешённый endpoint принимает или возвращает поля, которые этой роли недоступны.
Для CRM это три разные проверки: запросить чужого клиента, вызвать admin-only массовый export и отправить в PATCH поле owner_id или is_vip, которого нет в форме. Одной скрытой кнопкой ни один из этих рисков не закрывается.
Частые вопросы о доступе
Что правильнее для чужого приватного объекта: 403 или 404?
Оба варианта возможны по контракту. 404 скрывает сам факт существования объекта, 403 явно сообщает об отказе. Главное — единая политика, отсутствие утечки и невозможность действия.
Если id — UUID, BOLA невозможна?
Нет. UUID снижает возможность перебора, но id может попасть в ссылку, лог, экспорт или другой ответ. Сервер обязан проверять право на каждый объект независимо от формата id.
Достаточно ли проверить роли через UI?
Нет. Скрытый элемент улучшает UX, но запрос можно отправить напрямую. Авторизация должна действовать на сервере для каждого метода и объекта.
Проверка доступа маленькая по шагам и большая по последствиям: иногда один изменённый id показывает, защищает ли backend пользовательские данные на самом деле.