~/VibeHandbook
PDF бесплатно

Глава 18 · 04

Аутентификация против авторизации: эндпоинт, который может вызвать каждый

Эти два слова звучат похоже, а разница между ними — это место, где живут настоящие взломы.

  • Аутентификация (auth) — это кто ты? — вход в систему, доказательство личности.
  • Авторизация — это что тебе разрешено делать? — может ли этот залогиненный пользователь выполнить это действие с этими данными.

С аутентификацией AI справляется сносно; большую часть берут на себя библиотеки. На авторизации он стабильно проваливается, потому что авторизация специфична для правил вашего приложения, а их AI не знает. Хрестоматийная катастрофа:

// VULNERABLE: проверяет, что ты залогинен, но не КТО ты
app.get("/admin/export-all-users", requireLogin, (req, res) => {
  res.json(db.getAllUsers()); // любой залогиненный пользователь может это дёрнуть
});

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

// SAFE: подтверждает, что этот пользователь действительно админ
app.get("/admin/export-all-users", requireLogin, (req, res) => {
  if (!req.user.isAdmin) return res.status(403).send("Forbidden");
  res.json(db.getAllUsers());
});

Представьте две двери, через которые должен пройти запрос. Аутентификация спрашивает «вы вошли?»; авторизация спрашивает «можно ли вам делать это?». Брешь возникает, когда приложение строит первую дверь и забывает вторую:

  запрос ──▶  ┌──────────────────┐  ──▶ ┌──────────────────┐  ──▶  действ
              │ АУТЕНТИФИКАЦИЯ   │      │ АВТОРИЗАЦИЯ       │       вып.
              │ "вошёл?"         │      │ "можно ли ЭТОМУ   │
              │                  │      │  это ДЕЙСТВИЕ?"   │
              └──────────────────┘      └──────────────────┘
                  ✓ почти все              ✗ часто нет    
                    делают это               → вот взлом 

  ПРИМЕР — /admin/export-all-users 
     вошедший юзер ──▶ [auth ✓] ──▶ [ нет authz-проверки] ──▶ слиты ВСЕ юзеры
     вошедший юзер ──▶ [auth ✓] ──▶ [ isAdmin? → 403  ] ──▶ блокир. ✓   

Та же ловушка в миниатюре встречается повсюду: эндпоинт, который возвращает заказ #1234, не проверяя, что заказ принадлежит запрашивающему пользователю. Любой может поменять номер в и прочитать чужой заказ. Правило непарадное и абсолютное: проверяйте авторизацию на каждом эндпоинте, который касается данных, и не доверяйте ID, пришедшему от клиента. Не считайте скрытый URL безопасным только потому, что он скрыт — «никто не знает, что это существует» — это не средство защиты.

Хотите офлайн-версию?

Скачайте всю книгу в PDF или EPUB — бесплатно.