Broken Access Control

Broken Access Control — уязвимость, при которой пользователь получает доступ к ресурсам или действиям, выходящим за пределы его прав. OWASP #1 в Top 10 2021.

Зачем нужно

Неправильно настроенный контроль доступа позволяет злоумышленникам просматривать чужие данные, изменять права, удалять записи и выполнять привилегированные действия. Большинство взломов реальных систем (включая утечки IDOR) связаны именно с этой уязвимостью.

Где используется

  • REST API: проверка прав на уровне каждого эндпоинта
  • Панели администратора, защищённые только URL-адресом
  • Файловые хранилища с прямыми ссылками на объекты (IDOR)
  • Многоуровневые SaaS-приложения с ролями (admin / user / guest)

Основной контент

IDOR — Insecure Direct Object Reference

Самый частый случай: пользователь меняет ID в URL и получает чужие данные.

// УЯЗВИМО — нет проверки владельца
app.get('/api/orders/:id', async (req, res) => {
  const order = await Order.findById(req.params.id);
  res.json(order); // любой авторизованный пользователь видит любой заказ
});

// БЕЗОПАСНО — проверяем принадлежность
app.get('/api/orders/:id', authenticate, async (req, res) => {
  const order = await Order.findOne({
    _id: req.params.id,
    userId: req.user.id, // только свои заказы
  });
  if (!order) return res.status(404).json({ error: 'Not found' });
  res.json(order);
});

Вертикальное повышение привилегий

// УЯЗВИМО — роль берётся из тела запроса
app.post('/api/users', async (req, res) => {
  const user = await User.create(req.body); // злоумышленник передаёт role: 'admin'
  res.json(user);
});

// БЕЗОПАСНО — роль задаётся сервером
app.post('/api/users', async (req, res) => {
  const { name, email, password } = req.body;
  const user = await User.create({ name, email, password, role: 'user' });
  res.json(user);
});

Middleware для проверки ролей

function requireRole(...roles) {
  return (req, res, next) => {
    if (!roles.includes(req.user?.role)) {
      return res.status(403).json({ error: 'Forbidden' });
    }
    next;
  };
}

app.delete('/api/admin/users/:id', authenticate, requireRole('admin'), deleteUser);

Частые ошибки

  • Проверка прав только на фронтенде — легко обойти через DevTools или curl
  • Доверие полю role или isAdmin из JWT-payload без верификации подписи
  • Отсутствие проверки принадлежности объекта при операциях CRUD
  • Открытые эндпоинты администратора без проверки авторизации
  • Сокрытие функциональности через UI вместо ограничения на сервере

Связанные темы

Ресурсы