К основному контенту
secenta
СтатьяБесплатный урок10 мин

A01: Нарушение контроля доступа

Почему контроль доступа лидирует в OWASP Top 10: IDOR, path traversal, доверие скрытым полям и эскалация привилегий — и как закрыть это серверной авторизацией по каждому ресурсу.

текстЧто такое нарушение контроля доступа и почему это №1

Что это

Контроль доступа (access control) отвечает на вопрос: имеет ли право именно этот пользователь выполнить именно это действие с именно этим ресурсом? Аутентификация подтверждает, кто ты (логин и пароль), а авторизация решает, что тебе можно. Нарушение контроля доступа (Broken Access Control) — это когда система пускает пользователя туда, куда ему нельзя: к чужим заказам, к админ-панели, к чтению чужого файла.

Аналогия: представьте отель, где на дверях есть замки, но горничная по привычке открывает любую дверь любым ключом, потому что «постоялец же уже зашёл в здание через ресепшен». Войти в отель (аутентификация) и иметь право войти в конкретный номер (авторизация) — разные вещи.

В редакции OWASP Top 10 за 2021 год этот класс поднялся на первое место: уязвимости находили в 94% протестированных приложений. Причина популярности проста — проверку прав легко забыть. Разработчик добавляет новый эндпоинт, тестирует его под своей учёткой, видит, что данные приходят, и идёт дальше. Что произойдёт, если подставить чужой идентификатор, он не проверяет.

Первопричина

Глубинная причина почти всегда одна: сервер доверяет тому, что прислал клиент, и не перепроверяет права на каждый ресурс самостоятельно. Браузер показал пользователю только его заказы — значит, рассуждает разработчик, чужой заказ он и не запросит. Но злоумышленник не пользуется браузером как обычный человек: он напрямую формирует HTTP-запросы и подставляет любые значения.

Типичная ошибка: прятать кнопку «Удалить» от обычных пользователей на фронтенде и считать, что эндпоинт удаления защищён. Скрытие элемента интерфейса — это удобство, а не безопасность. Запрос DELETE /api/users/42 отправит и тот, у кого кнопки нет.

Мини-итог: контроль доступа — это серверная проверка права на конкретный ресурс при каждом обращении; она ломается, когда сервер верит клиенту на слово, и поэтому стабильно держит первое место в OWASP Top 10.

текстКак эксплуатируется: IDOR, path traversal, скрытые поля

IDOR — небезопасные прямые ссылки на объекты

IDOR (Insecure Direct Object Reference) — самый частый сценарий. Приложение использует идентификатор объекта прямо из запроса, не проверяя, принадлежит ли объект текущему пользователю. Вы заходите в свой заказ по адресу /api/orders/123. Меняете число на 124 — и видите чужой заказ с адресом доставки и телефоном другого человека.

Аналогия: гардеробные номерки идут по порядку. Если гардеробщик выдаёт пальто по номеру, не сверяя лицо, любой назовёт чужой номер и заберёт чужое пальто.

Подбор бывает прямым (последовательные числовые id) и не таким очевидным, когда id зашит в скрытое поле формы, в cookie или в JWT. Замена UUID на случайный почти невозможна перебором, но это не защита — это лишь усложнение. Если ссылка утечёт в лог, в реферер или в общий доступ, объект снова открыт. Настоящая защита — проверка владельца, а не непредсказуемость id.

Path traversal — выход за пределы каталога

Если приложение отдаёт файлы по имени из запроса (/download?file=report.pdf), злоумышленник подставляет последовательности ../, чтобы выбраться из разрешённой папки: /download?file=../../../../etc/passwd. Каждый ../ поднимает на каталог вверх, пока путь не упрётся в системные файлы. Встречаются и обходы фильтров: URL-кодирование (%2e%2e%2f), двойное кодирование, абсолютные пути.

Доверие скрытым полям и ролям с клиента

Ещё один класс — когда права или принадлежность передаются с клиента и принимаются как есть. Форма редактирования профиля шлёт role=user, и злоумышленник правит её на role=admin. Или в теле запроса есть userId, и сервер сохраняет данные под чужим идентификатором (mass assignment). Cookie вида isAdmin=false правится на true.

Типичная ошибка: хранить роль или признак владельца в редактируемом клиентом месте (скрытое поле, cookie, тело запроса) и читать оттуда при проверке прав. Источником истины должна быть серверная сессия или подписанный токен, сверенный с базой.

Мини-итог: IDOR ломает горизонтальную границу (чужие объекты того же уровня), path traversal вырывается из песочницы файловой системы, а доверие клиентским полям отдаёт врагу управление ролями — всё это варианты одной ошибки доверия вводу.

текстЭскалация привилегий и защита: авторизация на сервере, deny by default

Вертикальная и горизонтальная эскалация

Эскалацию привилегий принято делить на два вектора. Горизонтальная — доступ к ресурсам пользователя того же уровня: обычный клиент читает заказы другого обычного клиента (классический IDOR). Вертикальная — повышение уровня прав: рядовой пользователь получает доступ к функциям администратора, например к /admin/users или к эндпоинту смены чужого пароля.

Вертикальная эскалация часто живёт в незащищённых административных URL. Разработчик убрал ссылку на админку из меню обычных пользователей, но сам путь /admin/panel отвечает всем, кто его знает (это называют forced browsing — насильственный обход по угаданным адресам). Проверка роли на эндпоинте просто забыта.

Аналогия: горизонтальная эскалация — это зайти в соседний номер того же этажа; вертикальная — подняться на закрытый этаж для VIP, потому что лифт не спрашивает карту.

Как защититься — бьём в первопричину

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

  • Авторизация на сервере по каждому ресурсу. При каждом обращении сверяйте: владеет ли текущий пользователь (из сессии/токена) запрошенным объектом и разрешена ли ему операция. Для /api/orders/123 — это WHERE order.id = 123 AND order.owner_id = currentUser.id.
  • Deny by default. Доступ закрыт по умолчанию; открывается только явным правилом. Новый эндпоинт без правила должен отвечать 403, а не пускать всех.
  • Идентичность — только из серверного контекста. Кто пользователь и какая у него роль — берём из сессии или проверенного на сервере токена, никогда из тела запроса, cookie или скрытого поля.
  • Централизованный механизм. Одна общая прослойка проверки прав вместо копипасты в каждом обработчике — меньше шансов забыть.
  • Path traversal: канонизируйте путь и проверяйте, что он остаётся внутри разрешённого каталога; лучше — выдавайте по белому списку идентификаторов, а не по имени файла из запроса.
  • Логирование отказов доступа и алерты на всплески 403 — ранний признак перебора id.

Типичная ошибка: полагаться на «непредсказуемые» UUID вместо проверки владельца. Это безопасность через неясность; реальной границы она не создаёт.

Мини-итог: защита от A01 — это серверная авторизация по каждому ресурсу с принципом deny by default и идентичностью строго из серверного контекста; всё остальное (скрытие кнопок, случайные id) — лишь декорация.

кодIDOR: запрос и серверная проверка владельца
// Слева — что отправляет атакующий, ниже — разница между уязвимым и защищённым бэкендом. Для чужого объекта возвращаем 404, а не 403, чтобы не подтверждать его существование.
http
# Атакующий просто меняет id в адресе на чужой
GET /api/orders/123 HTTP/1.1
Host: shop.example.com
Cookie: session=eyJ1c2VyIjo3fQ...   # сессия пользователя #7

# Уязвимый бэкенд (псевдокод): берёт заказ по id, НЕ проверяя владельца
#   order = db.query("SELECT * FROM orders WHERE id = ?", req.params.id)
#   return order            <-- вернёт чужой заказ

# Правильно: владельца берём из сессии и включаем в условие
#   order = db.query(
#     "SELECT * FROM orders WHERE id = ? AND owner_id = ?",
#     req.params.id, session.userId)
#   if (!order) return res.status(404)   # не палим существование чужого объекта

Обсуждение

Задавайте вопросы — преподаватели и сокурсники ответят.

0 тем

Здесь пока тихо. Задайте первый вопрос — это поможет другим.