Аутентификация 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 key | 200 OK с данными |
| Отсутствующий API key | 401 Unauthorized |
| Невалидный/просроченный API key | 401 или 403 |
| Отозванный API key | 401 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 (самый распространённый для веб-приложений):
- Пользователь нажимает «Войти через Google»
- Приложение перенаправляет на сервер авторизации Google
- Пользователь входит и даёт разрешение
- Google перенаправляет обратно с кодом авторизации
- Приложение обменивает код на access token (сервер-к-серверу)
- Приложение использует access token для вызова API
Client Credentials Flow (сервер-к-серверу, без пользователя):
- Приложение отправляет client_id и client_secret на сервер аутентификации
- Сервер возвращает access token
- Приложение использует токен для вызова API
Ключевые токены в OAuth 2.0:
- Access Token — краткосрочный, используется для доступа к API (15 мин — 1 час)
- Refresh Token — долгосрочный, используется для получения новых access token (дни — месяцы)
Тестирование OAuth 2.0
| Тестовый сценарий | Ожидаемый результат |
|---|---|
| Валидный access token | 200 OK |
| Просроченный access token | 401 Unauthorized |
| Поток refresh token | Выдан новый access token |
| Просроченный refresh token | Принудительная повторная аутентификация |
| Невалидный scope | 403 Forbidden |
| Токен с недостаточным scope | 403 с ошибкой scope |
| Отозванный токен | 401 Unauthorized |
| Использование access token после logout | 401 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 | Название | Назначение |
|---|---|---|
sub | Subject | Идентификатор пользователя |
iat | Issued At | Когда создан токен |
exp | Expiration | Когда истекает токен |
iss | Issuer | Кто создал токен |
aud | Audience | Для кого предназначен токен |
role | Role | Права пользователя (пользовательский) |
Тестирование 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?
- Инвалидирует ли смена пароля существующие токены?
- Могут ли существовать несколько активных сессий одновременно?
Практическое упражнение
- Настройте тестирование JWT: Используйте jwt.io для создания и декодирования JWT. Модифицируйте claims и наблюдайте, что происходит при отправке изменённых токенов.
- Протестируйте потоки аутентификации: Используя публичный API, требующий аутентификации (GitHub API с personal access tokens), протестируйте сценарии валидной, невалидной и отсутствующей аутентификации.
- Создайте матрицу тестов: Для воображаемого API с ролями admin и user создайте матрицу endpoint-ов x ролей x ожидаемых кодов статуса.
- Протестируйте истечение токена: Если доступно, получите краткосрочный токен и проверьте, что он отклоняется после истечения.
Ключевые выводы
- Аутентификация проверяет личность (кто вы); авторизация проверяет права (что вы можете делать)
- API Keys просты, но ограничены — лучше всего для коммуникации сервер-к-серверу и rate limiting публичных API
- OAuth 2.0 — стандарт для доступа третьих сторон с множеством потоков для разных сценариев использования
- JWT — самодостаточные токены с header, payload и signature — payload читается кем угодно
- Всегда тестируйте полный жизненный цикл: валидные, просроченные, отозванные, изменённые и отсутствующие токены