7.04. Аутентификация и авторизация
Аутентификация и авторизация
Аутентификация и авторизация: основы доверия в цифровом взаимодействии
В мире распределённых систем, микросервисов и облачных платформ каждое взаимодействие между компонентами требует чёткого определения: кто инициирует запрос, и какие действия ему разрешены. Эти два аспекта — установление личности и предоставление прав — формируют фундамент безопасности при работе с программными интерфейсами. Они реализуются через два связанных, но принципиально разных процесса: аутентификацию и авторизацию.
Аутентификация: подтверждение личности
Аутентификация — это процесс проверки того, что субъект (пользователь, сервис, устройство) действительно является тем, за кого себя выдаёт. Это аналог предъявления паспорта на границе: документ не даёт права на въезд, но подтверждает, что человек — тот, кем он заявлен. В цифровом пространстве вместо паспорта используются учётные данные: пароли, сертификаты, токены или криптографические ключи.
Аутентификация отвечает на вопрос: «Кто ты?»
Она не определяет, что можно делать, а только устанавливает идентичность.
Авторизация: определение прав доступа
Авторизация — это процесс определения, какие ресурсы и действия доступны уже аутентифицированному субъекту. После того как личность подтверждена, система обращается к политикам доступа, чтобы понять, разрешено ли выполнить запрашиваемую операцию. Например, пользователь может войти в систему управления проектами, но не иметь права удалять задачи, созданные другими.
Авторизация отвечает на вопрос: «Что тебе разрешено делать?»
Она строится поверх аутентификации и зависит от ролей, прав, контекста запроса и других факторов.
Эти два процесса последовательны: сначала система узнаёт, кто перед ней, затем решает, что этому субъекту позволено. В некоторых сценариях, особенно в машинном взаимодействии, аутентификация и авторизация могут быть объединены в один шаг, но концептуально они остаются раздельными.
API-ключ: простой, но ограниченный механизм
Один из самых ранних и интуитивно понятных способов контроля доступа к API — использование API-ключа. Это уникальная строка символов, выдаваемая клиенту при регистрации в системе. Ключ передаётся с каждым запросом, обычно в заголовке X-API-Key или в параметре строки запроса.
Принцип работы
При регистрации приложения или пользователя в системе генерируется случайный, криптографически стойкий идентификатор — API-ключ. Этот ключ привязывается к учётной записи клиента в базе данных или конфигурации сервера. При получении запроса сервер извлекает ключ, сверяет его с внутренним реестром и, если совпадение найдено, считает запрос легитимным.
Пример запроса с API-ключом:
GET /api/v1/users HTTP/1.1
Host: service.example.com
X-API-Key: a1b2c3d4-e5f6-7890-g1h2-i3j4k5l6m7n8
Сервер проверяет, существует ли такой ключ, и если да — обрабатывает запрос.
Преимущества
- Простота реализации: не требует сложной логики, шифрования или внешних зависимостей.
- Лёгкость отслеживания: каждый ключ привязан к конкретному клиенту, что упрощает логирование, мониторинг и ограничение использования.
- Быстрый отзыв: ключ можно отозвать мгновенно, просто удалив его из реестра.
Ограничения и риски
API-ключ сам по себе не содержит информации о владельце, сроках действия или правах. Он лишь указывает на идентификатор клиента. Вся логика авторизации реализуется отдельно на стороне сервера.
Основной недостаток — отсутствие встроенной защиты от перехвата. Если ключ попадает в чужие руки (например, через логи, открытый репозиторий или сниффинг трафика), злоумышленник получает полный доступ к тем же возможностям, что и легальный владелец. Поэтому API-ключи обязательно должны передаваться только по защищённому соединению (HTTPS). Использование ключа в URL-параметрах дополнительно повышает риск его сохранения в логах прокси, браузеров или серверов.
Кроме того, API-ключ не поддерживает динамические права. Все запросы от одного клиента обрабатываются с одинаковым уровнем доступа, независимо от контекста. Это делает механизм непригодным для сложных сценариев, где права зависят от роли, времени суток, геолокации или типа операции.
Типичные сценарии использования
- Публичные API с ограничением по квоте (например, погодные сервисы, карты, переводчики).
- Внутренние микросервисы в доверенной среде, где трафик изолирован и шифрован на уровне сети.
- Прототипирование и быстрая интеграция, когда безопасность вторична по отношению к скорости разработки.
Для продакшн-сред с высокими требованиями к безопасности API-ключ используется либо в комбинации с другими механизмами (например, подписью запроса), либо заменяется на более надёжные подходы, такие как токены или mTLS.
JWT: самодостаточный токен с встроенной информацией
JSON Web Token (JWT) — это открытый стандарт (RFC 7519), определяющий компактный и самодостаточный способ передачи информации между сторонами в виде JSON-объекта. Эта информация может быть проверена и доверена, потому что она цифровым образом подписана. JWT часто используется для аутентификации пользователей и обмена данными между сервисами.
Структура JWT
Каждый JWT состоит из трёх частей, разделённых точками:
xxxxx.yyyyy.zzzzz
- Header — заголовок, содержащий тип токена (обычно
JWT) и алгоритм подписи (например,HS256илиRS256). - Payload — полезная нагрузка, содержащая утверждения (claims). Это могут быть стандартные поля (например,
iss— issuer,exp— expiration time), публичные или приватные данные. - Signature — подпись, созданная на основе кодированного заголовка, кодированной полезной нагрузки и секретного ключа (или приватного ключа при асимметричной криптографии).
Все три части кодируются в формате Base64Url, что делает токен легко передаваемым в URL, HTTP-заголовках или теле запроса.
Пример декодированного JWT:
Header
{
"alg": "HS256",
"typ": "JWT"
}
Payload
{
"sub": "1234567890",
"name": "Alexey Ivanov",
"role": "developer",
"iat": 1700000000,
"exp": 1700003600
}
Signature
(недекодируемая строка, вычисляемая по формуле: HMACSHA256(base64UrlEncode(header)+'.'+base64UrlEncode(payload), secret))
Как работает JWT в аутентификации
Типичный сценарий использования JWT в веб-приложении:
- Пользователь отправляет учётные данные (логин и пароль) на эндпоинт
/login. - Сервер проверяет их корректность.
- При успешной проверке сервер генерирует JWT, включая в payload идентификатор пользователя, роль, срок действия и другие атрибуты.
- Токен возвращается клиенту (обычно в теле ответа).
- Клиент сохраняет токен (в памяти, localStorage или cookie) и при каждом последующем запросе отправляет его в заголовке
Authorization: Bearer <token>. - Сервер получает токен, проверяет подпись, убеждается, что срок действия не истёк, и извлекает из payload информацию о пользователе.
- На основе этой информации принимается решение об авторизации.
Преимущества JWT
- Самодостаточность: вся необходимая информация содержится внутри токена. Серверу не нужно обращаться к базе данных для получения данных о пользователе при каждом запросе.
- Масштабируемость: отсутствие необходимости хранить сессии на сервере упрощает горизонтальное масштабирование. Любой экземпляр сервиса может проверить токен, если у него есть доступ к ключу подписи.
- Гибкость: можно включать любые утверждения, в том числе права доступа, метаданные, временные ограничения.
- Поддержка кросс-доменных сценариев: JWT легко передавать между доменами, что важно для микросервисных архитектур и SPA-приложений.
Риски и ограничения
JWT не лишён недостатков, особенно в контексте безопасности.
- Невозможность отзыва до истечения срока: если токен скомпрометирован, отозвать его до окончания
expнельзя, если только не внедрена дополнительная логика (например, чёрный список токенов или короткий срок жизни). - Хранение на клиенте: если токен хранится в localStorage, он уязвим к XSS-атакам. Если в HttpOnly cookie — защищён от XSS, но потенциально уязвим к CSRF (если не применены меры защиты).
- Подделка при неправильной конфигурации: если сервер принимает токены с алгоритмом
noneили не проверяет алгоритм подписи, возможна подделка токена. - Раздутие размера: при включении большого объёма данных в payload токен становится тяжелее, что увеличивает объём трафика, особенно при частых запросах.
Когда использовать JWT
JWT особенно эффективен в следующих сценариях:
- Аутентификация в stateless-сервисах (REST API, микросервисы).
- Передача контекста между доверенными системами (например, между фронтендом и бэкендом, или между внутренними сервисами).
- Реализация одноразовых токенов (например, для сброса пароля), где срок действия короткий, а риск компрометации минимален.
JWT не подходит для долгосрочных сессий без механизма отзыва, а также для систем, где требуется мгновенная инвалидация прав доступа (например, при блокировке пользователя администратором).
OAuth 2.0: делегирование доступа без передачи учётных данных
OAuth 2.0 — это протокол авторизации, позволяющий одному сервису (клиенту) получить ограниченный доступ к ресурсам пользователя на другом сервисе (провайдере), не требуя от пользователя передачи своих учётных данных (логина и пароля). Вместо этого пользователь явно разрешает клиенту действовать от его имени в рамках заданных прав.
OAuth 2.0 не является протоколом аутентификации, хотя часто используется в связке с OpenID Connect для этой цели. Его основная задача — делегирование полномочий.
Основные участники
В экосистеме OAuth 2.0 выделяют четыре ключевых роли:
- Resource Owner — субъект, владеющий ресурсами (обычно конечный пользователь).
- Resource Server — сервер, хранящий защищённые ресурсы (например, API профиля, почты, фото).
- Client — приложение, запрашивающее доступ к ресурсам (веб-сайт, мобильное приложение, бэкенд-сервис).
- Authorization Server — сервер, выдающий токены доступа после подтверждения согласия пользователя.
Типичный поток: Authorization Code Flow
Самый распространённый и безопасный поток для веб-приложений — Authorization Code Flow. Он состоит из следующих этапов:
-
Перенаправление на сервер авторизации
Клиент перенаправляет пользователя в браузере на эндпоинт/authorizeпровайдера, указывая:client_id— идентификатор зарегистрированного приложения,redirect_uri— URI, на который вернётся пользователь после согласия,scope— запрашиваемые права (например,read:profile,write:messages),state— случайная строка для защиты от CSRF.
-
Согласие пользователя
Пользователь вводит свои учётные данные на сайте провайдера и видит запрос на предоставление прав клиенту. Если он соглашается, провайдер перенаправляет его обратно наredirect_uriс временным authorization code в параметре URL. -
Обмен кода на токен
Клиент (уже на серверной стороне) отправляет этот код на эндпоинт/tokenпровайдера вместе сclient_id,client_secretиredirect_uri. В ответ получает access token (и, опционально, refresh token). -
Доступ к ресурсам
Клиент использует access token для обращения к Resource Server, передавая его в заголовкеAuthorization: Bearer <token>. Сервер проверяет токен и, если он валиден и имеет нужные права, возвращает запрошенные данные.
Другие потоки (grant types)
OAuth 2.0 поддерживает несколько типов потоков в зависимости от типа клиента и уровня доверия:
- Implicit Flow — устаревший поток, при котором токен возвращался напрямую в браузер. Использовался для SPA, но сейчас заменён на Authorization Code Flow с PKCE.
- Client Credentials Flow — используется для машинного взаимодействия, когда клиент сам по себе является ресурсом (например, микросервис, обращающийся к другому микросервису). Не требует участия пользователя.
- Password Grant — позволяет клиенту напрямую обменивать логин и пароль на токен. Рекомендуется только для доверенных приложений (например, официальных мобильных приложений компании) и постепенно выводится из употребления.
- Refresh Token Flow — механизм продления сессии. Когда access token истекает, клиент может запросить новый, используя refresh token, без повторного ввода учётных данных.
Безопасность и лучшие практики
- Использование PKCE (Proof Key for Code Exchange) — обязательная мера для публичных клиентов (SPA, мобильные приложения), предотвращающая перехват authorization code.
- Короткий срок жизни access token — снижает риск при компрометации.
- Хранение client_secret только на сервере — никогда не встраивается в клиентский код.
- Валидация redirect_uri — предотвращает перенаправление на злонамеренные сайты.
- Использование HTTPS на всех этапах — без исключений.
Примеры использования
- «Войти через Google» — классический пример OAuth 2.0 в связке с OpenID Connect.
- Интеграция CRM с почтовым сервисом для отправки писем от имени пользователя.
- Мобильное приложение, получающее доступ к медиатеке пользователя в облаке.
OAuth 2.0 обеспечивает гибкость, безопасность и контроль над тем, какие именно действия разрешены третьей стороне. Он стал основой для современных систем единого входа (SSO) и межсервисного взаимодействия.
mTLS: аутентификация на уровне соединения
Transport Layer Security (TLS) — это криптографический протокол, обеспечивающий конфиденциальность, целостность и подлинность данных при передаче по сети. В стандартной конфигурации TLS используется односторонняя аутентификация: клиент проверяет сертификат сервера, чтобы убедиться, что он взаимодействует с настоящим сервисом, а не с подменённым. Сервер при этом не проверяет личность клиента.
Mutual TLS (mTLS) расширяет этот подход, добавляя обязательную аутентификацию клиента. В этом режиме и клиент, и сервер предъявляют друг другу цифровые сертификаты, подписанные доверенным центром сертификации (CA). Только если оба сертификата действительны и подписаны доверенным CA, соединение устанавливается.
Как работает mTLS
- Клиент инициирует TLS-рукопожатие, отправляя
ClientHello. - Сервер отвечает
ServerHello, своим сертификатом и запросом на клиентский сертификат (CertificateRequest). - Клиент проверяет сертификат сервера (обычно с учётом цепочки доверия и отзыва через CRL/OCSP).
- Если проверка пройдена, клиент отправляет свой сертификат и цифровую подпись, подтверждающую владение закрытым ключом.
- Сервер проверяет клиентский сертификат аналогичным образом.
- При успешной взаимной проверке устанавливается зашифрованное соединение.
Весь процесс происходит на уровне транспорта, до передачи любого HTTP-запроса. Это означает, что даже попытка отправить запрос без валидного сертификата будет отклонена на этапе установки соединения.
Преимущества mTLS
- Сильная аутентификация: сертификаты трудно подделать, особенно при использовании аппаратных модулей безопасности (HSM) или защищённых хранилищ ключей.
- Защита от подмены клиента: только сущности с валидным сертификатом могут установить соединение.
- Отсутствие зависимости от уровня приложения: аутентификация выполняется до обработки бизнес-логики, что снижает нагрузку на приложение и упрощает аудит.
- Интеграция с сетевой политикой: в сервис-мешах (например, Istio, Linkerd) mTLS используется для автоматического шифрования и аутентификации трафика между микросервисами.
Требования и сложности
mTLS требует развитой инфраструктуры управления сертификатами:
- Центра сертификации (CA) — для выпуска и отзыва сертификатов.
- Автоматизированного жизненного цикла — сертификаты имеют ограниченный срок действия, и их нужно регулярно обновлять.
- Безопасного хранения закрытых ключей — утечка ключа даёт злоумышленнику полный доступ.
- Согласованной политики доверия — все участники должны использовать один и тот же корневой CA или иметь взаимное доверие между CA.
Развертывание mTLS вручную — задача нетривиальная. Однако современные платформы (Kubernetes с Istio, HashiCorp Vault, AWS Private CA, SPIFFE/SPIRE) значительно упрощают управление сертификатами и автоматизацию.
Пример: mTLS в микросервисной архитектуре
Представим систему из трёх сервисов: auth-service, payment-service, user-service. Без mTLS любой сервис, способный достичь порта другого, может отправить запрос. С mTLS:
payment-serviceпринимает соединения только от тех клиентов, чьи сертификаты подписаны внутренним CA.- При попытке подключения от неавторизованного источника (например, скрипта с внешнего IP) соединение разрывается на уровне TLS.
- Даже если злоумышленник получит доступ к сети кластера, он не сможет имитировать легитимный сервис без валидного сертификата.
Это соответствует принципу Zero Trust: «никому не доверяй, всегда проверяй».
Когда использовать mTLS
- Внутренние коммуникации между микросервисами в доверенной, но изолированной среде.
- Системы с высокими требованиями к безопасности (финансы, здравоохранение, критическая инфраструктура).
- Сценарии, где требуется гарантия подлинности источника на уровне сети, независимо от реализации приложения.
- Интеграции с внешними партнёрами, где обмен данными должен быть строго ограничен известными участниками.
mTLS не предназначен для взаимодействия с конечными пользователями через браузеры — браузеры не поддерживают автоматическую загрузку клиентских сертификатов в большинстве случаев. Его сфера — машинное взаимодействие (M2M).
Сравнение и комбинирование механизмов: стратегии защиты API
Каждый из рассмотренных механизмов — API-ключ, JWT, OAuth 2.0, mTLS — решает определённую задачу в цепочке доверия. Никакой из них не является универсальным решением. На практике современные системы используют комбинацию этих подходов, применяя каждый на своём уровне и для своей цели.
Уровни защиты и зоны ответственности
Можно выделить три основных уровня, на которых реализуется контроль доступа:
- Транспортный уровень — обеспечивает подлинность участников соединения и защиту канала. Здесь доминирует mTLS.
- Уровень приложения (API) — определяет, кто делает запрос и какие действия разрешены. Здесь применяются API-ключи, JWT, OAuth 2.0.
- Бизнес-логика — принимает окончательное решение о выполнении операции на основе контекста (например, «пользователь может редактировать только свои документы»). Этот уровень использует данные, полученные из токенов или сессий.
Эти уровни дополняют друг друга. Например, mTLS гарантирует, что запрос пришёл от легитимного микросервиса, а JWT внутри этого запроса указывает, от имени какого пользователя действует сервис.
Сценарии применения
Сценарий 1: Публичный API для сторонних разработчиков
- Основной механизм: API-ключ + квоты.
- Дополнительно: JWT для операций, требующих привязки к пользователю (если API поддерживает user-scoped endpoints).
- Почему: простота интеграции, чёткий учёт использования, минимальные требования к клиенту.
- Безопасность: обязательный HTTPS, регулярная ротация ключей, мониторинг аномалий.
Сценарий 2: Внутренние микросервисы в Kubernetes-кластере
- Основной механизм: mTLS (автоматически управляется сервис-мешем, например Istio).
- Дополнительно: JWT в заголовках для передачи контекста пользователя (например,
x-user-id,x-roles). - Почему: mTLS защищает сеть от несанкционированного доступа, JWT позволяет сохранять семантику запроса без обращения к центральному сервису аутентификации.
- Безопасность: автоматическая выдача и обновление сертификатов, политики сетевого доступа (NetworkPolicy), аудит трафика.
Сценарий 3: Мобильное приложение, обращающееся к бэкенду
- Основной механизм: OAuth 2.0 с Authorization Code Flow + PKCE.
- Дополнительно: короткоживущие JWT как access token, refresh token для продления сессии.
- Почему: безопасная авторизация без передачи пароля, поддержка отзывов через инвалидацию refresh token, совместимость с OpenID Connect для единого входа.
- Безопасность: хранение refresh token в защищённом хранилище (Keychain, Android Keystore), использование HTTPS, валидация
stateиcode_verifier.
Сценарий 4: B2B-интеграция между двумя компаниями
- Основной механизм: mTLS + подписанные JWT.
- Почему: mTLS гарантирует, что соединение установлено только с доверённым партнёром; JWT содержит детали операции, подписаны закрытым ключом отправителя и проверяются публичным ключом получателя.
- Безопасность: обмен корневыми сертификатами, регулярный аудит, двухфакторное согласование изменений в политике доступа.
Ошибки проектирования и анти-паттерны
- Хранение API-ключа в клиентском коде — делает его общедоступным. Такой ключ не обеспечивает реальной безопасности, только идентификацию.
- Использование JWT без проверки подписи — приводит к возможности подделки прав доступа.
- Долгоживущие токены без механизма отзыва — увеличивают окно уязвимости при компрометации.
- Отказ от mTLS в доверенной сети — нарушает принцип Zero Trust; внутренняя сеть не считается безопасной.
- Смешивание аутентификации и авторизации в одном поле токена — затрудняет аудит и гибкое управление правами.
Рекомендации для DevOps-инженера
- Начинайте с модели угроз. Определите, кто ваш противник: внешний злоумышленник, недобросовестный партнёр, скомпрометированный микросервис?
- Применяйте защиту в глубину. Не полагайтесь на один механизм. Используйте mTLS для канала, токены для контекста, RBAC для бизнес-логики.
- Автоматизируйте управление секретами. Используйте Vault, AWS Secrets Manager, Kubernetes Secrets с ограничением доступа по принципу наименьших привилегий.
- Логируйте и мониторьте. Записывайте все попытки аутентификации, особенно неудачные. Интегрируйте с SIEM-системами.
- Регулярно проводите аудит конфигураций. Убедитесь, что все эндпоинты защищены, нет «забытых» открытых API, сроки действия сертификатов и токенов соответствуют политике.