Внедрение аутентификации и авторизации в приложениях без серверов
Почему аутентификация и авторизация важны в архитектурах без серверов
Бессерверные вычисления изменили способ создания и развертывания приложений командами, абстрагируя управление инфраструктурой, уменьшая операционные накладные расходы и позволяя автоматизировать масштабирование. Однако эфемерный, событийный характер бессерверных функций создает уникальные проблемы безопасности. Без постоянного сервера для поддержания состояния сеанса каждый вызов функции должен независимо проверять, кто звонит и разрешено ли им выполнять запрошенное действие. Это делает аутентификацию (проверка личности) и авторизацию (предоставление разрешений) основополагающими для любого готового к производству бессерверного приложения. Хорошо разработанный уровень защиты конфиденциальных данных предотвращает несанкционированный доступ и обеспечивает соблюдение правил, таких как GDPR, HIPAA или SOC 2.
В отличие от монолитных приложений, где логика аутентификации может жить внутри центрального сервера, приложения без сервера распространяют аутентификацию через шлюзы API, службы идентификации и отдельные функции. Это распределение требует четкой стратегии, которая уравновешивает безопасность, производительность и опыт разработчиков. В этой статье мы исследуем основные концепции, популярные инструменты и практические шаблоны реализации для защиты приложений без сервера.
Аутентификация против авторизации: четкое различие
Хотя часто используется взаимозаменяемо, аутентификация и авторизация служат различным целям. Аутентификация отвечает на вопрос «Кто вы?» - обычно путем проверки учетных данных, таких как имя пользователя и пароль, одноразовый код или биометрический фактор. Авторизация отвечает на вопрос «Что вам разрешено делать?» - проверка разрешений после установления личности.
В безсерверных средах аутентификация часто происходит на шлюзе API или через выделенного поставщика идентификационных данных (IdP) до запуска функции. Авторизация может обрабатываться на уровне шлюза через политические документы, в функции через код, который проверяет претензии в JSON Web Token (JWT), или через комбинацию обоих. Неспособность разделить эти обязанности часто приводит к уязвимостям, таким как эскалация привилегий или утечка данных.
Стратегии аутентификации для приложений без серверов
Серверная аутентификация обычно подразделяется на три категории: полностью управляемые сторонние службы, пользовательская аутентификация в рамках функций и федеративная идентификация с использованием OAuth2 / OpenID Connect. Каждый подход предлагает компромиссы между простотой реализации, контролем и стоимостью.
Сторонние поставщики удостоверений личности
Большинство бессерверных приложений полагаются на выделенный IdP для обработки аутентификации. Эти службы управляют каталогами пользователей, хешированием паролей, управлением сеансами и интеграцией с поставщиками социальных входов. Популярные варианты включают в себя:
- Amazon Cognito — полностью управляемый сервис, который изначально интегрируется с AWS API Gateway и Lambda. Cognito предоставляет пулы пользователей для регистрации/подписи, пулы идентификации для временных учетных данных AWS и поддерживает MFA, адаптивную аутентификацию и пользовательские рабочие процессы с помощью триггеров Lambda.Официальная документация
- Auth0 — облачная платформа идентификации, предлагающая универсальный логин, социальные связи, вход без пароля и обширную настройку. Auth0 предоставляет SDK для нескольких языков и может быть интегрирован с любым шлюзом API.Документация Auth0
- Firebase Authentication — часть пакета Firebase от Google, он поддерживает электронную почту/пароль, телефон и популярных социальных провайдеров. Firebase Auth плавно интегрируется с Firebase Functions и Cloud Run.
- Azure Active Directory B2C — Для корпоративных приложений, требующих интеграции Azure AD, B2C обеспечивает управление идентификацией для приложений, ориентированных на потребителя, с поддержкой стандартов, таких как OAuth2 и SAML.
Использование стороннего IdP перегружает бремя безопасного хранения учетных данных, шифрования и соблюдения. Это также упрощает реализацию расширенных функций, таких как MFA, восстановление учетной записи и защита от грубой силы.
Пользовательская аутентификация в бессерверных функциях
Когда вам нужен полный контроль над потоком аутентификации — например, при интеграции с устаревшей базой данных пользователей или при обеспечении соблюдения собственных протоколов аутентификации — вы можете реализовать логику аутентификации непосредственно внутри Lambda или другой функции без сервера. Этот шаблон часто используется для конечных точек API, которые должны быть общедоступными, но требуют пользовательского токена, такого как ключи API для внешних партнеров.
Однако создание пользовательской аутентификации с нуля является рискованным. Функции без сервера не имеют состояния, поэтому вы должны безопасно обрабатывать хеширование паролей (с использованием bcrypt или Argon2), генерацию токенов и управление сеансами. Холодные запуски могут вызвать всплески задержки, если логика аутентификации тяжела. По этим причинам пользовательская аутентификация лучше всего зарезервирована для внутренних служб или некритических пользовательских баз.
OAuth2 и OpenID Connect в безсерверном режиме
OAuth2 является отраслевым стандартом для делегированного авторизации, позволяя приложениям получать доступ к ресурсам от имени пользователя без совместного использования учетных данных. OpenID Connect (OIDC) использует OAuth2 для добавления проверки личности. Многие приложения без сервера используют потоки OAuth2 / OIDC, чтобы позволить пользователям войти в систему с Google, GitHub или Facebook, а затем выпускать JWT, которые несут претензии пользователей. шлюзы API могут проверять эти токены без вызова функции, снижая задержку и стоимость.
Социальный логин и MFA
Социальный вход в систему часто является самым простым способом уменьшить трение во время регистрации. И Google, и GitHub аутентификация может быть интегрирована через SDK платформы или путем реализации потока кода авторизации OAuth2 вручную. Парирование социального входа с MFA добавляет дополнительный уровень безопасности: даже если социальная учетная запись скомпрометирована, злоумышленник не может получить доступ к безсерверному приложению без второго фактора. Большинство IdP поддерживают MFA из коробки, но вы должны настроить его в панели инструментов IdP и необязательно обеспечить его для чувствительных операций.
Токен-ориентированная аутентификация: основа бессерверной аутентификации
Поскольку функции без сервера не имеют состояния, токены - особенно JSON Web Tokens (JWT) - являются предпочтительным механизмом передачи информации аутентификации и авторизации между службами. JWT - это компактный, безопасный для URL-адресов токен, который состоит из заголовка, полезной нагрузки (требований) и подписи. Подпись гарантирует, что токен не был подделан. IdPs подписывают токены с закрытым ключом, а ваши функции без сервера проверяют подпись с помощью открытого ключа, часто динамически извлекаемого из хорошо известной конечной точки.
Структура и валидация JWT
Типичная JWT выглядит как . Полезная нагрузка содержит стандартные претензии (выпуск, предмет, истечение срока действия) и пользовательские претензии (роли, разрешения, идентификатор пользователя). В безсерверном контексте функции проверяют подпись, истечение срока действия и эмитент токена перед тем, как продолжить. Многие облачные провайдеры предлагают предварительно созданные авторизаторы Lambda или авторизаторы API Gateway JWT, которые автоматически обрабатывают валидацию токена, возвращая политику IAM, которая предоставляет или отказывает в доступе к конечной точке.
Например, при использовании Auth0 с AWS Lambda вы настраиваете пользовательский авторизатор, который проверяет токен на конечную точку JWKS Auth0. Авторизатор затем прикрепляет декодированные претензии к контексту события, позволяя Lambda принимать мелкозернистые решения о авторизации без повторной проверки токена.
Сессия против аутентификации токенов
Традиционные серверные приложения полагаются на сеансовые файлы cookie, хранящиеся на сервере. В безсерверных сессиях становятся трудными, потому что функции эфемерны и масштабирование до нуля может нарушить хранилища сеансов в памяти. Аутентификация на основе токенов сдвигает состояние на клиента: токен несет всю необходимую информацию, и серверу нужно только проверить свою подпись. Этот подход без состояния масштабируется легко, но требует осторожных стратегий отзыва токенов (например, использование черных списков токенов или короткое время истечения срока действия в сочетании с обновлениями токенов).
Модели авторизации для Serverless
После установления подлинности личность определяется авторизацией. Три распространенные модели: Role-Based Access Control (RBAC), Attribute-Based Access Control (ABAC) и Policy-Based Access Control (PBAC).
Управление доступом на основе ролей (RBAC)
В RBAC разрешения группируются в роли (например, администратор, редактор, зритель). Пользователям назначается одна или несколько ролей, и система проверяет, позволяет ли роль пользователя запрошенное действие. RBAC прост в реализации: после декодирования JWT проверьте, содержит ли претензия на роль требуемую роль для конечной точки. Это хорошо работает для приложений с четко определенными иерархиями пользователей.
Атрибутный контроль доступа (ABAC)
ABAC оценивает доступ на основе комбинации пользовательских атрибутов (например, отдел, уровень клиренса), атрибутов ресурсов (например, классификация документов) и условий окружающей среды (например, время суток, IP-адрес). Например, пользователь может просматривать документы только в своем собственном отделе в рабочее время. ABAC является более гибким, чем RBAC, но вводит сложность. В безсерверных политиках ABAC часто оцениваются в функции авторизации с использованием механизма правил, такого как Open Policy Agent (OPA).
Управление доступом на основе политики (PBAC)
PBAC централизует политику авторизации вне кода приложения. Облачные сервисы, такие как AWS Identity and Access Management (IAM), позволяют определять политики JSON, которые определяют, какие действия разрешены на каких ресурсах. Эти политики могут быть прикреплены к ролям, принимаемым функцией или сессией пользователя. В сочетании с API Gateway вы можете принудительно осуществлять авторизацию без написания кода — шлюз оценивает политику перед вызовом функции. Этот шаблон особенно эффективен для микросервисов, где согласованность между службами имеет решающее значение.
Внедрение авторизации в приложениях без сервера
Существует три основных уровня, на которых авторизация может быть обеспечена: в шлюзе API (до запуска функции), внутри авторизатора Lambda или внутри самой функции.
API Gateway Authorization (сборник)
AWS API Gateway, Azure API Management и Google Cloud Endpoints поддерживают нативную валидацию JWT и авторизацию на основе политики. Например, HTTP API API API Gateway может проверять JWT от определенного эмитента, а затем отображать претензии к разрешениям маршрута. Этот подход быстрый, потому что валидация происходит на границе сети, уменьшая вызовы и стоимость Lambda. Однако он поддерживает только простые проверки ролей; сложные условия по-прежнему требуют пользовательского авторизатора.
Авторизующий функционал Lambda
Авторизатор Lambda (ранее известный как пользовательский авторизатор) - это функция, которая получает токен (как заголовок на предъявителя или параметр запроса) и возвращает политику IAM, которую обеспечивает API Gateway. Авторизатор может декодировать JWT, вызывать внешнюю службу или запрашивать базу данных для определения разрешений пользователя. Поскольку авторизатор сам по себе является функцией без сервера, он может реализовать любую логику. Однако он добавляет задержку - обычно на 50-200 мс больше на запрос - и может стать узким местом, если не разработан тщательно. Чтобы смягчить холодные запуски, держать авторизатор наклонным и рассмотреть возможность использования авторизатора Token (против «REQUEST») для более простой проверки токена.
Прямое авторизация внутри функций
В некоторых архитектурах, особенно тех, которые не связаны с шлюзом API (например, функциями, управляемыми событиями, резолятерами GraphQL), авторизация должна происходить внутри функции. Этот шаблон включает в себя декодирование JWT и проверку разрешений на базе данных или кэше. Хотя он гибкий, он может привести к дублированию логики между функциями. Для поддержания согласованности используйте общую библиотеку промежуточного программного обеспечения, которая обертывает ваши обработчики функций.
Например, используя промежуточное ПО для Lambda, вы можете создать промежуточное ПО для авторизации, которое анализирует JWT, проверяет роли и либо возвращает ответ 403, либо передает управление обработчику.
Лучшие практики для безопасной аутентификации и авторизации без сервера
Помимо выбора правильных инструментов и шаблонов, безопасный безсерверный уровень аут-пространства требует соблюдения лучших практик эксплуатации. Следующие рекомендации взяты из документации облачного провайдера и руководящих принципов OWASP.
Используйте HTTPS везде
Все коммуникации между клиентами, шлюзом API и бэкэнд-функциями должны быть зашифрованы с помощью TLS. Для мобильных клиентов может быть добавлено закрепление сертификатов, но убедитесь, что сертификаты регулярно вращаются.
Наименьшее преимущество
Каждая функция должна получать только необходимые ей разрешения. Используйте для функций Lambda четко определенные роли IAM и избегайте назначения широких разрешений, таких как . Аналогично, авторизаторы шлюзов API должны возвращать политики, ограничивающие доступ к конкретным ресурсам.
Многофакторная аутентификация (MFA)
Включите MFA для любой чувствительной операции, особенно конечных точек администратора. IdP, такие как Cognito и Auth0, поддерживают MFA с помощью TOTP или SMS. В безсерверном режиме вы можете принудительно проверить MFA для конкретных маршрутов API, проверив претензию в JWT (например, ).
Проверка токенов на каждой границе
Не думайте, что токен, переданный одной функции, уже был подтвержден службой восходящего потока. Каждая функция должна независимо проверять подпись, истечение срока действия и эмитента токена. Эта защита в глубине предотвращает одну точку отказа.
Управляйте секретами безопасно
Никогда не используйте ключи API жесткого кода, секретные ключи или учетные данные базы данных в функциональном коде. Используйте менеджер секретов, такой как AWS Secrets Manager, AWS SSM Parameter Store или HashiCorp Vault. Для локальной разработки используйте переменные среды с осторожностью и никогда не связывайте их с контролем версий.
Регулярно вращайте ключи
Вращайте ключи подписи, ключи API и секреты клиентов по регулярному расписанию (например, каждые 90 дней). Автоматизируйте вращение с помощью инструментов облачного провайдера. Для JWT убедитесь, что URL открытого ключа (конечная точка JWKS) обновляется до истечения срока действия старых ключей, чтобы избежать сбоев проверки.
Лог и мониторинг доступа
Включите подробную регистрацию журналов доступа к шлюзу API и журналов Lambda CloudWatch. Мониторинг ненормальных шаблонов, таких как повторяющиеся ошибки 401, необычные географические местоположения или попытки доступа к несанкционированным ресурсам. Настройка оповещений с использованием таких сервисов, как AWS CloudWatch Alarms или сторонние инструменты SIEM.
Ограничение ставок и дросселирование
Используйте планы использования шлюза API, дросселирование или WAF (брандмауэр веб-приложений) для защиты конечных точек аутентификации (например, /login) от атак грубой силы. Ограничения параллелизма функций Lambda также могут предотвратить внезапный всплеск запросов auth от подавляющих IdP.
Тестирование подлинной логики
Напишите единичные тесты и интеграционные тесты для вашего кода аутентификации и авторизации. Включите тесты для просроченных токенов, неправильно сформированных токенов, отсутствующих претензий и попыток обойти авторизацию. Используйте такие инструменты, как для насмешек над событиями шлюза API.
Оставайтесь в курсе патчей безопасности
Экосистема без серверов быстро развивается. Подписывайтесь на рекомендации по безопасности от вашего провайдера IdP и облачных сервисов. Регулярно применяйте исправления к версиям и зависимостям среды выполнения Lambda (например, библиотеки JWT, HTTP-клиенты).
Заключение
Аутентификация и авторизация не являются дополнительными функциями в приложениях без серверов — они имеют основополагающее значение для укрепления доверия к пользователям и защиты конфиденциальных данных. Используя управляемых поставщиков идентификационных данных, аутентификацию на основе токенов и многоуровневые модели авторизации, вы можете создать безопасную основу, которая масштабируется по мере роста вашей пользовательской базы. Модели, описанные в этой статье — сторонние IdP, проверка JWT, авторизаторы шлюзов API и RBAC / ABAC — проверены в производственных средах и адаптируются к любому крупному облачному провайдеру.
Помните, что безопасность - это непрерывная практика, а не одноразовая конфигурация. Регулярно просматривайте свои политики аута, журналы аудита и зависимости от обновлений. При правильном подходе бессерверная аутентификация и авторизация становятся активаторами, а не препятствиями для создания быстрых, безопасных и масштабируемых приложений. Для дальнейшего чтения обратитесь к Top Ten OWASP и JWT.io для лучших практик проверки токенов.