Lesson 20 of 26

Урок 20 — Авторизация и Аутентификация

Название: Authentication vs Authorization — кто ты и что тебе можно
Описание: Разбираем два фундаментальных понятия безопасности: аутентификацию (кто ты?) и авторизацию (что тебе разрешено?). Изучаем JWT, OAuth, сессии и как всё это тестировать.
Почему это важно для QA: Ошибки в аутентификации и авторизации — одни из наиболее критичных уязвимостей. Тестировщик, который не умеет их проверять, пропустит баги с потенциально катастрофическими последствиями.


1. Ключевые определения

Аутентификация (Authentication / AuthN)

«Кто ты?» — процесс проверки личности пользователя.

Пользователь утверждает: «Я Иван Петров»
Система проверяет: «Докажи» → пароль, биометрия, SMS-код
Результат: «Да, ты действительно Иван Петров»

Авторизация (Authorization / AuthZ)

«Что тебе разрешено?» — процесс определения прав доступа после подтверждения личности.

Система знает: «Ты — Иван Петров, роль = Manager»
Запрос: «Хочу удалить пользователя»
Система проверяет: «У Manager нет права удалять пользователей»
Результат: 403 Forbidden

Аналогия

Аутентификация = пропуск на работу (доказывает, кто ты)
Авторизация    = уровень доступа (в какие кабинеты тебя пустят)

Ты показываешь пропуск охраннику → прошёл аутентификацию
Пытаешься войти в серверную → нет доступа → не авторизован

2. Разница в одной таблице

КритерийАутентификацияАвторизация
Вопрос«Кто ты?»«Что тебе можно?»
КогдаПервымПосле аутентификации
ПроверяетЛичностьПрава доступа
Ошибка при провале401 Unauthorized403 Forbidden
ПримерыЛогин/пароль, JWT, OAuthРоли, разрешения, ACL

3. Методы аутентификации

3.1 Логин и пароль (Basic Auth)

Классический способ. Пользователь вводит Email + Password, сервер проверяет в БД.

Проблема: пароли нужно хранить безопасно (bcrypt, Argon2, scrypt)
Никогда: не хранить пароли в открытом виде или MD5

3.2 Session-based Authentication

1. Пользователь входит с логином/паролем
2. Сервер создаёт запись в БД: sessions { id: "abc123", userId: 42, expiresAt: ... }
3. Сервер отправляет Cookie: sessionId=abc123
4. При каждом запросе браузер отправляет Cookie
5. Сервер ищет сессию в БД и получает данные пользователя

Плюсы: можно немедленно инвалидировать сессию (выход из аккаунта)
Минусы: нужно хранить сессии на сервере (не подходит для масштабирования)

3.3 JWT (JSON Web Token)

Токен, содержащий информацию о пользователе, подписанный сервером.

Структура JWT: header.payload.signature

Пример:
eyJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOjQyLCJyb2xlIjoiYWRtaW4iLCJleHAiOjE3MjAzNDU2Nzh9.xxxxx

Декодированный payload:
{
  "userId": 42,
  "role": "admin",
  "exp": 1720345678   ← время истечения (Unix timestamp)
}

Плюсы: не нужно хранить на сервере, хорошо масштабируется
Минусы: нельзя отозвать до истечения (если не использовать блэклист)

Как работает JWT:
1. Пользователь входит → сервер создаёт JWT и подписывает секретным ключом
2. JWT отправляется клиенту (в Cookie или LocalStorage)
3. Клиент отправляет JWT в заголовке: Authorization: Bearer <token>
4. Сервер проверяет подпись → доверяет данным в payload

3.4 OAuth 2.0 / OpenID Connect

Позволяет авторизоваться через сторонние сервисы (Google, GitHub, Facebook).

Сценарий: «Войти через Google»
1. Пользователь нажимает «Войти через Google»
2. Редирект на Google (accounts.google.com/oauth/...)
3. Пользователь разрешает доступ
4. Google редиректит обратно с кодом: /callback?code=xyz
5. Сервер меняет code на access_token у Google
6. Сервер получает данные пользователя у Google
7. Создаёт сессию / JWT для пользователя

3.5 Multi-Factor Authentication (MFA)

Добавляет второй фактор к паролю:

Фактор 1 (знание): пароль
Фактор 2 (владение): SMS-код, TOTP (Google Authenticator), hardware key
Фактор 3 (биометрия): отпечаток пальца, распознавание лица

4. Модели авторизации

4.1 RBAC (Role-Based Access Control)

Самая распространённая модель. Права привязаны к роли.

Роли:
├── Guest    → может читать публичный контент
├── User     → может редактировать свой профиль, создавать заказы
├── Manager  → может управлять заказами, видеть аналитику
└── Admin    → полный доступ ко всему

Пользователь получает роль → наследует все права роли

4.2 ABAC (Attribute-Based Access Control)

Права зависят от атрибутов пользователя, ресурса и контекста.

Правило: Пользователь может редактировать документ,
         ЕСЛИ document.authorId == user.id
         И    user.department == document.department
         И    currentTime < document.deadline

4.3 ACL (Access Control List)

Список разрешений на конкретный ресурс.

Файл /reports/q1-2026.pdf:
├── User #42 → READ
├── User #43 → READ, WRITE
└── Role "Admin" → READ, WRITE, DELETE

5. Как тестировать аутентификацию

5.1 Позитивные тесты (happy path)

TC-01: Вход с корректными логином и паролем
TC-02: Вход с помощью Google OAuth
TC-03: Вход с MFA (корректный TOTP)
TC-04: «Запомнить меня» — сессия сохраняется после перезапуска браузера
TC-05: Выход — сессия завершается, Cookie удаляется

5.2 Негативные тесты

TC-06: Неверный пароль → 401, ошибка «Неверный логин или пароль»
TC-07: Несуществующий email → 401 (НЕ «Пользователь не найден» — это утечка данных!)
TC-08: Пустые поля → ошибка валидации
TC-09: Блокировка после N неудачных попыток (brute-force protection)
TC-10: Истёкший JWT → 401, требует повторной авторизации
TC-11: Невалидный JWT (изменена подпись) → 401
TC-12: MFA с неверным кодом → 401
TC-13: Повторное использование ссылки «Сброс пароля» → 410 Gone или ошибка

6. Как тестировать авторизацию

6.1 Тест ролевой модели

Матрица доступа для теста:

Действие              | Guest | User | Manager | Admin
──────────────────────┼───────┼──────┼─────────┼──────
Просмотр каталога     |  ✓    |  ✓   |    ✓    |  ✓
Создание заказа       |  ✗    |  ✓   |    ✓    |  ✓
Отмена своего заказа  |  ✗    |  ✓   |    ✓    |  ✓
Отмена чужого заказа  |  ✗    |  ✗   |    ✓    |  ✓
Управление товарами   |  ✗    |  ✗   |    ✓    |  ✓
Управление пользоват. |  ✗    |  ✗   |    ✗    |  ✓

6.2 Тест горизонтального доступа (IDOR)

Insecure Direct Object Reference — самый частый тип уязвимости авторизации.

Пользователь #42 делает запрос:
GET /api/orders/1001   ← заказ #1001 принадлежит пользователю #42 → OK

Что если поменять ID?
GET /api/orders/1002   ← заказ #1002 принадлежит пользователю #99

Ожидаем: 403 Forbidden
Баг (IDOR): 200 OK + данные чужого заказа

Это критический баг! Всегда проверяй!

6.3 Тест вертикального доступа

Пользователь с ролью User пытается:
DELETE /api/admin/users/99

Ожидаем: 403 Forbidden
Баг: 200 OK (User может удалять пользователей как Admin)

7. Пример тестов в Playwright

typescripttypescript
import { test, expect } from "@playwright/test";
import { LoginPage } from "../pages/LoginPage";
import { ApiClient } from "../utils/ApiClient";

const USERS = {
  regular: { email: "user@test.com", password: "TestPass123", role: "user" },
  admin: { email: "admin@test.com", password: "AdminPass123", role: "admin" },
} as const;

test.describe("Авторизация — IDOR тест", () => {
  test("пользователь не видит заказ другого пользователя", async ({ request }) => {
    const userApi = new ApiClient(request);
    await userApi.login(USERS.regular.email, USERS.regular.password);

    // Получаем ID заказа другого пользователя (Admin)
    const adminApi = new ApiClient(request);
    await adminApi.login(USERS.admin.email, USERS.admin.password);
    const adminOrders = await adminApi.get("/api/orders");
    const otherUserOrderId = adminOrders.body[0].id;

    // Пробуем получить чужой заказ от имени обычного пользователя
    const response = await userApi.get(`/api/orders/${otherUserOrderId}`);

    expect(
      response.status,
      "Пользователь не должен видеть чужие заказы (IDOR)"
    ).toBe(403);
  });
});

test.describe("Авторизация — вертикальный доступ", () => {
  test("обычный пользователь не может вызвать admin API", async ({ request }) => {
    const userApi = new ApiClient(request);
    await userApi.login(USERS.regular.email, USERS.regular.password);

    const response = await userApi.delete("/api/admin/users/99");

    expect(
      response.status,
      "Обычный пользователь не может вызывать Admin API"
    ).toBe(403);
  });
});

8. Распространённые уязвимости (OWASP Top 10)

УязвимостьОписаниеКак тестировать
Broken AuthenticationСлабые пароли, нет блокировки brute-forceПопробовать 100 неверных паролей
Broken AuthorizationIDOR, доступ к чужим даннымПодменить userId в URL/запросе
Sensitive Data ExposureПароли в открытом виде в URLПроверить URL и логи
JWT VulnerabilitiesАлгоритм «none», слабый секретДекодировать и изменить JWT
Session FixationСессия не меняется после входаПроверить sessionId до и после входа

9. Частые ошибки при тестировании

Тестируют только happy path
→ Всегда проверяй IDOR — это один из самых критичных и частых багов.

Не проверяют сообщения об ошибках
→ «Пользователь с таким email не существует» — это утечка данных! Должно быть: «Неверный логин или пароль».

Забывают тестировать после смены роли
→ Пользователь получил Admin → потом Admin отозвали → старый JWT всё ещё работает?


Итог

АУТЕНТИФИКАЦИЯ (AuthN) = «Кто ты?»
├── Методы: пароль, JWT, OAuth, MFA
├── Ошибка: 401 Unauthorized
└── Тестируем: вход, выход, неверные данные, истёкший токен

АВТОРИЗАЦИЯ (AuthZ) = «Что тебе можно?»
├── Модели: RBAC, ABAC, ACL
├── Ошибка: 403 Forbidden
└── Тестируем: ролевую матрицу, IDOR, вертикальный доступ

КЛЮЧЕВОЕ ПРАВИЛО: сначала аутентификация, потом авторизация
САМЫЙ ОПАСНЫЙ БАГ: IDOR — пользователь видит данные другого