Аутентификация vs. авторизация

Прежде чем погружаться в механизмы, разберитесь с двумя концепциями:

  • Аутентификация (AuthN) — «Кто вы?» Проверка личности клиента, делающего запрос.
  • Авторизация (AuthZ) — «Что вы можете делать?» Определение ресурсов и действий, к которым аутентифицированный клиент имеет доступ.

Пользователь может быть аутентифицирован (вошёл в систему), но не авторизован (не имеет прав) для удаления чужого аккаунта. Тестирование обоих аспектов критически важно.

Аутентификация по API Key

Простейшая форма аутентификации API. Сервер выдаёт уникальный ключ, который клиент включает в каждый запрос.

Как это работает

GET /api/weather?city=London HTTP/1.1
Host: api.weather.com
X-API-Key: sk_live_abc123def456

Или как query-параметр (менее безопасно):

GET /api/weather?city=London&api_key=sk_live_abc123def456

Тестирование API Keys

Тестовый сценарийОжидаемый результат
Валидный API key200 OK с данными
Отсутствующий API key401 Unauthorized
Невалидный/просроченный API key401 или 403
Отозванный API key401 Unauthorized
API key от другого окружения401/403
Превышен rate limit для ключа429 Too Many Requests
API key в URL vs в заголовкеОба должны работать (или URL должен быть отклонён)

Проблемы безопасности

  • API keys никогда не должны быть в URL (они появляются в логах сервера и истории браузера)
  • Ключи должны передаваться только по HTTPS
  • Ключи должны иметь ограниченные права (только чтение vs чтение-запись)

Basic Authentication

Отправляет имя пользователя и пароль, закодированные в Base64, с каждым запросом. Просто, но не очень безопасно.

Как это работает

GET /api/users HTTP/1.1
Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=

Значение после «Basic» — это username:password, закодированные в Base64. Это не шифрование — любой, перехвативший запрос, может декодировать его.

Тестирование Basic Auth

# Закодировать учётные данные
echo -n "admin:secret123" | base64
# Результат: YWRtaW46c2VjcmV0MTIz

# Использовать в запросе
curl -H "Authorization: Basic YWRtaW46c2VjcmV0MTIz" https://api.example.com/users

Тестовые сценарии: валидные учётные данные, неправильный пароль, несуществующий пользователь, пустые учётные данные, некорректный Base64.

OAuth 2.0

Отраслевой стандарт авторизации. OAuth 2.0 позволяет сторонним приложениям получать доступ к ресурсам пользователя без передачи паролей.

Потоки OAuth 2.0

Authorization Code Flow (самый распространённый для веб-приложений):

  1. Пользователь нажимает «Войти через Google»
  2. Приложение перенаправляет на сервер авторизации Google
  3. Пользователь входит и даёт разрешение
  4. Google перенаправляет обратно с кодом авторизации
  5. Приложение обменивает код на access token (сервер-к-серверу)
  6. Приложение использует access token для вызова API

Client Credentials Flow (сервер-к-серверу, без пользователя):

  1. Приложение отправляет client_id и client_secret на сервер аутентификации
  2. Сервер возвращает access token
  3. Приложение использует токен для вызова API

Ключевые токены в OAuth 2.0:

  • Access Token — краткосрочный, используется для доступа к API (15 мин — 1 час)
  • Refresh Token — долгосрочный, используется для получения новых access token (дни — месяцы)

Тестирование OAuth 2.0

Тестовый сценарийОжидаемый результат
Валидный access token200 OK
Просроченный access token401 Unauthorized
Поток refresh tokenВыдан новый access token
Просроченный refresh tokenПринудительная повторная аутентификация
Невалидный scope403 Forbidden
Токен с недостаточным scope403 с ошибкой scope
Отозванный токен401 Unauthorized
Использование access token после logout401 Unauthorized

JSON Web Tokens (JWT)

JWT — компактный, самодостаточный формат токена, широко используемый для аутентификации. Он позволяет серверу верифицировать токен без обращения к базе данных.

Структура JWT

JWT состоит из трёх частей, разделённых точками: header.payload.signature

eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkFsaWNlIn0.signature

Header (алгоритм и тип):

{
  "alg": "HS256",
  "typ": "JWT"
}

Payload (claims — данные пользователя):

{
  "sub": "1234567890",
  "name": "Alice",
  "role": "admin",
  "iat": 1716239022,
  "exp": 1716242622
}

Signature (верификация):

HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)

Важные JWT Claims

ClaimНазваниеНазначение
subSubjectИдентификатор пользователя
iatIssued AtКогда создан токен
expExpirationКогда истекает токен
issIssuerКто создал токен
audAudienceДля кого предназначен токен
roleRoleПрава пользователя (пользовательский)

Тестирование JWT-аутентификации

Тесты валидации токена:

  • Валидный токен — 200 OK
  • Просроченный токен — 401 Unauthorized
  • Изменённый payload (модифицированные claims) — 401 (невалидная подпись)
  • Отсутствующая подпись — 401
  • Токен, подписанный неправильным секретом — 401
  • Токен с alg: none — 401 (критический тест безопасности)

Тесты жизненного цикла токена:

  • Проверить, что токен содержит ожидаемые claims после логина
  • Проверить, что просроченные токены отклоняются
  • Протестировать, что поток refresh генерирует новый валидный токен
  • Проверить, что старые токены невалидны после смены пароля
  • Протестировать работу токена на разных endpoint-ах API

Декодирование JWT для тестирования (используйте jwt.io или командную строку):

# Декодировать payload (средняя часть)
echo "eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkFsaWNlIn0" | base64 -d

Распространённые уязвимости аутентификации для тестирования

1. Нарушенная аутентификация

  • Можно ли получить доступ к защищённым endpoint-ам без токена?
  • Принимает ли API токены после того, как они должны быть инвалидированы?
  • Передаются ли пароли в открытом виде?

2. Манипуляция токенами

  • Можно ли модифицировать claims JWT и продолжать получать доступ к ресурсам? (слабая/отсутствующая проверка подписи)
  • Обходит ли alg: none верификацию подписи?
  • Можно ли использовать токен из одного окружения в другом?

3. Защита от перебора (Brute Force)

  • Есть ли блокировка после нескольких неудачных попыток входа?
  • Применяются ли rate limit-ы к endpoint-ам аутентификации?
  • Раскрывают ли сообщения об ошибках факт существования пользователя?

4. Управление сессиями

  • Инвалидируются ли токены при logout?
  • Инвалидирует ли смена пароля существующие токены?
  • Могут ли существовать несколько активных сессий одновременно?

Практическое упражнение

  1. Настройте тестирование JWT: Используйте jwt.io для создания и декодирования JWT. Модифицируйте claims и наблюдайте, что происходит при отправке изменённых токенов.
  2. Протестируйте потоки аутентификации: Используя публичный API, требующий аутентификации (GitHub API с personal access tokens), протестируйте сценарии валидной, невалидной и отсутствующей аутентификации.
  3. Создайте матрицу тестов: Для воображаемого API с ролями admin и user создайте матрицу endpoint-ов x ролей x ожидаемых кодов статуса.
  4. Протестируйте истечение токена: Если доступно, получите краткосрочный токен и проверьте, что он отклоняется после истечения.

Ключевые выводы

  • Аутентификация проверяет личность (кто вы); авторизация проверяет права (что вы можете делать)
  • API Keys просты, но ограничены — лучше всего для коммуникации сервер-к-серверу и rate limiting публичных API
  • OAuth 2.0 — стандарт для доступа третьих сторон с множеством потоков для разных сценариев использования
  • JWT — самодостаточные токены с header, payload и signature — payload читается кем угодно
  • Всегда тестируйте полный жизненный цикл: валидные, просроченные, отозванные, изменённые и отсутствующие токены