Код-ревью Senior Авторизация: IDOR, RBAC, ABAC обновлено
Ревью: мультиарендный обработчик на Go
Вопрос
Найдите проблемы изоляции арендаторов и авторизации.
func listInvoices(w http.ResponseWriter, r *http.Request) {
tenant := r.Header.Get("X-Tenant-ID")
status := r.URL.Query().Get("status")
rows, err := db.Query("SELECT id, amount, customer FROM invoices WHERE tenant_id = $1 AND status = $2", tenant, status)
if err != nil {
http.Error(w, err.Error(), 500)
return
}
writeJSON(w, scan(rows))
}
func getInvoice(w http.ResponseWriter, r *http.Request) {
id := chi.URLParam(r, "id")
row := db.QueryRow("SELECT id, amount, customer FROM invoices WHERE id = $1", id)
writeJSON(w, scanOne(row))
}
Коротко
Список защищён фильтром, но фильтр берёт значение у клиента, а детальный просмотр фильтра не имеет. Типичная картина: проверку сделали в одном месте и забыли в другом.
Что должен найти ревьюер
- Безопасностьстрока 2Арендатор берётся из заголовка, который задаёт клиент: подставив чужой
X-Tenant-ID, можно читать счета любой организации. Брать tenant из проверенного токена или сессии. - Безопасностьстрока 6Текст ошибки БД уходит клиенту.
- Безопасностьстрока 14Детальный просмотр не фильтрует по арендатору вовсе: BOLA по id счёта.
- Ошибкастрока 8
rowsне закрываются (defer rows.Close()). - Стильстрока 14Нет проверки прав пользователя внутри организации (роль на просмотр финансов).
Разбор
Список защищён фильтром, но фильтр берёт значение у клиента, а детальный просмотр фильтра не имеет. Типичная картина: проверку сделали в одном месте и забыли в другом. Надёжнее единый слой данных с tenant из контекста и RLS.
Ответьте сами, а не прочитайте
В тренажёре вопрос попадёт в повторения и вернётся, когда начнёт забываться. Плюс билеты с зачётом: 20 вопросов, не больше 2 ошибок.