
IDOR (Insecure Direct Object Reference, небезопасная прямая ссылка на объект) — это уязвимость, при которой приложение показывает или изменяет данные по идентификатору, но не проверяет, принадлежит ли объект текущему пользователю. Меняем id в запросе — и получаем чужой заказ, документ, счёт или профиль. Звучит примитивно, но именно этот класс годами возглавляет рейтинги: в OWASP Top 10 2021 категория A01: Broken Access Control (куда входит IDOR) вышла на первое место, а по данным OWASP признаки нарушения контроля доступа находят в 94% протестированных приложений. Это одна из самых частых находок и на нашем пентесте веб-приложений.
Как выглядит атака: пошагово
Представим личный кабинет интернет-магазина. Пользователь открывает свой заказ, и браузер отправляет запрос:
GET /api/orders/1043 HTTP/1.1
Host: shop.example.com
Authorization: Bearer eyJhbGciOi...
--- ответ ---
200 OK
{ "order_id": 1043, "user": "alice", "total": 5400, "address": "..." }Атакующий просто уменьшает номер на единицу — GET /api/orders/1042 — и если сервер не проверяет владельца, в ответ приходит чужой заказ с адресом и суммой. Дальше атака автоматизируется: скрипт перебирает 1..100000 и выкачивает базу заказов целиком. Это называется enumeration (перечисление).
IDOR прячется не только в числовых id
- UUID и хэши. Кажется безопасным, но если UUID где-то утекает (в списках, логах, реферере) — доступ открыт.
- Параметры тела и заголовки.
{"account_id": 55}в POST,X-User-Id: 55в заголовке. - Имена файлов.
/download?file=invoice_1042.pdf. - Косвенные ссылки.
/api/users/me/cardsvs/api/users/55/cards— второй вариант часто забывают закрыть.
Почему сканеры это пропускают
Автоматический сканер видит, что endpoint /api/orders/1042 вернул 200 OK, и считает его «рабочим». Он не понимает бизнес-контекст — что заказ 1042 принадлежит другому пользователю. Чтобы найти IDOR, нужен ручной тест с двумя аккаунтами: заходим под пользователем A, пытаемся обратиться к ресурсам пользователя B. Именно так работаем мы, и именно поэтому IDOR — «ручная» уязвимость.
Экспертное наблюдение: 8 из 10 критичных IDOR, которые мы находим, живут не в основном сценарии, а на «второстепенных» действиях — экспорт в PDF, повторная отправка письма, отмена заказа, вебхуки. Разработчики закрывают доступ на чтение, но забывают про операции записи и служебные ручки.
Инструменты для поиска IDOR
- Burp Suite + расширение Autorize / AuthMatrix — автоматически повторяет каждый запрос от имени другого пользователя и подсвечивает, где доступ не заблокирован.
- Burp Intruder — перебор идентификаторов для проверки enumeration.
- ffuf / turbo intruder — быстрый перебор на больших диапазонах.
- Двухаккаунтная матрица вручную — самый надёжный метод: таблица «роль × ресурс × действие».
Как защититься: рабочие меры с примерами
Ключевой принцип: проверять владельца на сервере при каждом обращении к объекту, а не полагаться на то, что UI не покажет лишнюю ссылку. Плохой и хороший код:
// ❌ УЯЗВИМО: берём объект по id из запроса без проверки владельца
app.get("/api/orders/:id", (req, res) => {
const order = db.orders.find(req.params.id);
res.json(order); // вернёт ЛЮБОЙ заказ
});
// ✅ БЕЗОПАСНО: объект ищется в scope текущего пользователя
app.get("/api/orders/:id", (req, res) => {
const order = db.orders.findOne({
id: req.params.id,
user_id: req.user.id // владелец берётся из сессии/токена, НЕ из запроса
});
if (!order) return res.sendStatus(404);
res.json(order);
});- Авторизация на уровне объекта. Проверяйте не «залогинен ли пользователь», а «имеет ли ОН право на ЭТОТ объект».
- Владелец — из сессии, а не из запроса.
user_idберётся из токена/сессии сервера, клиент не должен его передавать. - Централизуйте контроль доступа. Единый слой (middleware, policy) вместо проверок «руками» в каждом обработчике — так вы не забудете закрыть новую ручку.
- Deny by default. Доступ запрещён, пока явно не разрешён.
- Возвращайте 404, а не 403, для чужих объектов — не подтверждайте их существование.
- Логируйте отказы доступа и алертите на всплески — это признак enumeration-атаки.
Чек-лист самопроверки
- Может ли пользователь A получить объект пользователя B, поменяв id? (проверьте GET, POST, PUT, DELETE)
- Закрыты ли экспорт, вебхуки, повторные отправки, отмена — не только основной просмотр?
- Проверяется ли владелец на API так же строго, как в вебе?
- Что произойдёт при переборе id скриптом — есть ли rate limit и алерты?
IDOR почти никогда не «висит один»: в мульти-арендных (multi-tenant) продуктах он превращается в cross-tenant утечку — один клиент видит данные другого. Это уже не баг, а инцидент с уведомлением регулятора по 152-ФЗ.
Уверены, что пользователи не видят чужие данные?
Проверим контроль доступа двухаккаунтным тестом на всех ролях и ручках — найдём IDOR раньше злоумышленников.
Читайте также: Пентест API, Пентест SaaS, Безопасность API (OWASP API Top 10).