В логе доступа одна сессия читает три id счетов подряд — найдите и исправьте дефект обработчика
В логе доступа одна аутентифицированная сессия запрашивает /api/invoices/1041, затем 1042, затем 1043 за несколько секунд, и каждый ответ — 200. Этот обработчик обслуживает маршрут.
Ограничения:
req.user.id— аутентифицированный пользователь, выставлен доверенной middlewaredb.invoices.findByIdпринимает только id счёта и не учитывает вызывающего- ответ не должен раскрывать, существует ли счёт другого аккаунта
app.get('/api/invoices/:id', requireLogin, async (req, res) => {
const invoice = await db.invoices.findById(req.params.id);
if (!invoice) return res.status(404).json({ error: 'not found' });
res.json(invoice);
});
Найдите и исправьте уязвимость.
Обработчик аутентифицирует, но не авторизует — он загружает счёт по id, поэтому вошедший читает чужую запись. Ограничьте выборку владельцем из сессии и отвечайте 404 при расхождении.
- ✗Принимать
requireLoginза проверку авторизации, а не аутентификации - ✗Чинить формат идентификатора вместо добавления ограничения по владельцу
- ✗Отвечать 403 на чужой объект, подтверждая тем самым его существование
- →Почему ограничение запроса безопаснее загрузки с последующей сверкой?
- →Какой тест докажет, что маршрут закрыт для второго аккаунта?
Обработчик проверяет только факт входа. db.invoices.findById ничего не знает о вызывающем, поэтому любой аутентифицированный пользователь получает чужой счёт — это нарушение авторизации на уровне объектов (BOLA), и последовательные id делают соседнюю запись очевидной.
Правильное исправление — ограничить саму выборку владельцем, а не загружать запись и сверять её после. Ответ на чужой счёт совпадает с ответом на несуществующий, поэтому наличие записи не раскрывается.
app.get('/api/invoices/:id', requireLogin, async (req, res) => {
const invoice = await db.invoices.findByIdForOwner(req.params.id, req.user.id);
if (!invoice) return res.status(404).json({ error: 'not found' });
res.json(invoice);
});
Проверка обязана выполняться на каждом запросе и на каждом методе маршрута, а не только на чтении.