Представьте ресурс, доступный любому аутентифицированному пользователю по идентификатору в запросе. Как проверить, что доступ к чужому объекту запрещён?
Нужно проверить авторизацию на уровне объекта: отправить запрос к объекту, принадлежащему другому пользователю, сохранив действительную аутентификацию, и убедиться, что сервер отказывает в доступе. Наличие входа в систему подтверждает только личность пользователя, но не его право работать с каждым конкретным объектом.
В ранних веб-приложениях разработчики часто считали достаточной проверку факта входа пользователя. Идентификатор объекта передавался клиентом, а сервер напрямую использовал его без проверки владельца или разрешений.
Так возник класс ошибок, известный как IDOR, а в современной терминологии BOLA — нарушение авторизации на уровне объекта. Подход к тестированию сформировался как реакция на необходимость проверять не только аутентификацию, но и каждое решение о доступе.
Пусть пользователь имеет право просматривать объект с идентификатором A. Если он заменяет этот идентификатор на B, принадлежащий другому пользователю, сервер должен заново проверить разрешение на объект B.
Неверная реализация возвращает чужие данные, позволяет изменить объект или удалить его. Это может привести к утечке персональных данных, несанкционированным изменениям и нарушению изоляции между клиентами.
Тест строится на нескольких учетных записях с различными ролями и наборами объектов. Для каждой операции проверяют как минимум четыре случая: доступ владельца разрешён, доступ постороннего пользователя запрещён, доступ пользователя с недостаточной ролью запрещён, доступ к несуществующему объекту обрабатывается безопасно.
Важно сохранять действительную сессию атакующего пользователя. Иначе тест будет проверять аутентификацию, а не авторизацию. Также следует проверять не только чтение, но и изменение, удаление, экспорт, скачивание файлов и косвенные операции, например добавление участника к объекту.
Проверка должна выполняться на сервере для каждого запроса и каждого объекта. Скрытие идентификаторов в интерфейсе, последовательная нумерация, случайные идентификаторы или отключение кнопки в клиенте не заменяют серверную проверку разрешений.
Безопасный отказ должен не раскрывать лишние сведения. В некоторых системах используют единый ответ для отсутствующего и недоступного объекта, чтобы не позволять угадывать существование данных; однако точный статус может быть оправдан внутренним API, если он не создаёт нежелательного раскрытия информации.
Автоматизация полезна для перебора матрицы ролей и объектов, но сама по себе не доказывает корректность модели доступа. Нужно заранее определить владельцев, участников, границы организаций и наследование разрешений.
В многоклиентском сервисе пользователь мог просматривать документы своей организации. При ручной проверке интерфейс не показывал чужие документы, поэтому первоначально рассматривались два варианта: считать интерфейс достаточной защитой или проверять серверную авторизацию через две тестовые организации.
Первый вариант был быстрее, но не защищал от прямых запросов и не проверял изоляцию данных. Второй требовал подготовки тестовых данных, зато позволял установить, что решение о доступе принимается сервером.
Выбрали второй вариант и проверили чтение, изменение и скачивание документов. Чтение оказалось защищено, но операция скачивания использовала отдельный обработчик без проверки организации. После добавления общей серверной проверки разрешений и регрессионных тестов скачивание чужих документов стало невозможным, а разрешённые операции сохранились.
Нет. Случайный или длинный идентификатор снижает вероятность угадывания, но не является проверкой полномочий. Идентификатор может попасть в журналы, историю браузера, ссылки, сообщения, резервные копии или ответы другого API. Если полученный идентификатор принимается без проверки права доступа, ошибка сохраняется.
Нет. Для каждой операции может использоваться отдельный путь обработки и отдельная политика доступа. Объект может быть защищён при просмотре, но доступен через скачивание, поиск, экспорт, массовую операцию, изменение или удаление. Полноценная проверка строит матрицу субъектов, объектов и действий.
Нужно разделять право получить содержимое и право узнать факт существования. Сервер может скрывать содержимое, но выдавать различающиеся статусы, размеры ответа или сообщения, по которым можно перечислять чужие объекты. Поэтому проверяют не только данные в ответе, но и статус, тело, заголовки, время обработки и побочные эффекты. Требуемое поведение определяется моделью угроз и контрактом API, но оно должно быть единообразным для всех способов обращения к объекту.