Эта страница переведена автоматически. Прочитайте оригинальную версию на английском здесь.

Шпаргалка по Passkeys. Практические рекомендации, шаблоны внедрения и KPI для программ passkeys.
Обеспечение безопасной и простой аутентификации пользователей — обязательное требование для цифровых компаний в 2024 году. Ключи доступа (passkeys), как новый стандарт входа в систему, являются идеальным решением для удовлетворения этих потребностей. Однако повышенное удобство и безопасность ключей доступа для пользователей обходятся разработчикам дорогой ценой при их реализации. Сложность внедрения связана с тем, что ключи доступа — относительно новая технология не только для пользователей, но и для разработчиков, и их реализация может быть довольно сложной по сравнению с аутентификацией на основе паролей. На самом деле для аутентификации по ключам доступа требуется как минимум четыре конечные точки API, в то время как для аутентификации по паролю — всего одна.
Одним из основных компонентов на стороне сервера для обеспечения аутентификации с помощью ключей доступа является сервер WebAuthn (зеленая часть библиотеки). Подробное руководство по интеграции сервера WebAuthn в более широкую корпоративную архитектуру см. в нашей отдельной статье.
Источник: Yubico
В этой статье блога мы сравниваем несколько библиотек / пакетов / SDK серверов WebAuthn, анализируем их различия и даем рекомендации разработчикам, которые только начинают внедрять ключи доступа.
Последние статьи
Чтобы лучше понять, зачем вообще нужна библиотека сервера WebAuthn, давайте посмотрим, как можно внедрить ключи доступа. В принципе, существует два способа интеграции ключей доступа на веб-сайты и в приложения:
Хотя стороннее решение легко интегрировать, и оно обычно экономит много времени инженеров (особенно на пограничные случаи, обслуживание, восстановление, резервные варианты и улучшенный UX), некоторые разработчики предпочитают реализовывать все самостоятельно.
Попробуйте passkeys в live demo.
Давайте посмотрим, как работает самостоятельная реализация ключей доступа. В самой базовой настройке необходим механизм для регистрации (sign-up) и аутентификации (login). Оба процесса, также называемые церемониями WebAuthn, обрабатываются по-разному, хотя общий поток следует похожей схеме:
PublicKeyCredentialCreationOptions и PublicKeyCredentialRequestOptions соответственно. Одной из важнейших частей этих параметров является вызов (challenge). Затем параметры WebAuthn отправляются обратно на фронтенд.Поскольку каждый процесс регистрации или входа включает эти этапы, бэкенду необходимо отслеживать пользователей, ключи доступа и запросы.
Igor Gjorgjioski
Head of Digital Channels & Platform Enablement, VicRoads
We hit 80% mobile passkey activation across 5M+ users without replacing our IDP.
See how VicRoads scaled passkeys to 5M+ users — alongside their existing IDP.
Read the case studyЕсли вы хотите получить более глубокие знания о том, как работают ключи доступа, и как выглядит простая реализация (без использования сторонних решений), вы можете изучить нашу статью в блоге здесь.
В реальных сценариях при самостоятельной реализации ключей доступа имейте в виду, что дело не только в предоставлении необходимых конечных точек API и базовой реализации. Кроме того, вам необходимо решить следующие задачи и сценарии использования:
Тем не менее, для базовой реализации вам нужно лишь придерживаться стандарта WebAuthn. Использования хорошо известной и поддерживаемой библиотеки сервера WebAuthn обычно достаточно. Библиотека генерирует параметры и проверяет вызовы при входе, по сути, беря на себя криптографическую и самую сложную часть.
Присоединяйтесь к нашему Passkeys Community для обновлений и поддержки.
Все проанализированные библиотеки предоставляют необходимые функции для аутентификации по ключам доступа. Поэтому мы уделили особое внимание следующим критериям:
Были проанализированы следующие библиотеки серверов WebAuthn (отсортированы по убыванию количества звезд на GitHub в декабре 2023 года):
Посмотрите, сколько людей действительно используют passkeys.
type UserModel = { id: string; username: string; currentChallenge?: string; }; /** * It is strongly advised that authenticators get their own DB * table, ideally with a foreign key to a specific UserModel. * * "SQL" tags below are suggestions for column data types and * how best to store data received during registration for use * in subsequent authentications. */ type Authenticator = { // SQL: Encode to base64url then store as `TEXT`. Index this column credentialID: Uint8Array; // SQL: Store raw bytes as `BYTEA`/`BLOB`/etc... credentialPublicKey: Uint8Array; // SQL: Consider `BIGINT` since some authenticators return atomic timestamps as counters counter: number; // SQL: `VARCHAR(32)` or similar, longest possible value is currently 12 characters // Ex: 'singleDevice' | 'multiDevice' credentialDeviceType: CredentialDeviceType; // SQL: `BOOL` or whatever similar type is supported credentialBackedUp: boolean; // SQL: `VARCHAR(255)` and store string array as a CSV string // Ex: ['usb' | 'ble' | 'nfc' | 'internal'] transports?: AuthenticatorTransport[]; };
public class StoredCredential { /// <summary> /// The Credential ID of the public key credential source. /// </summary> public byte[] Id { get; set; } /// <summary> /// The credential public key of the public key credential source. /// </summary> public byte[] PublicKey { get; set; } /// <summary> /// The latest value of the signature counter in the authenticator data from any ceremony using the public key credential source. /// </summary> public uint SignCount { get; set; } /// <summary> /// The value returned from getTransports() when the public key credential source was registered. /// </summary> public AuthenticatorTransport[] Transports { get; set; } /// <summary> /// The value of the BE flag when the public key credential source was created. /// </summary> public bool IsBackupEligible { get; set; } /// <summary> /// The latest value of the BS flag in the authenticator data from any ceremony using the public key credential source. /// </summary> public bool IsBackedUp { get; set; } /// <summary> /// The value of the attestationObject attribute when the public key credential source was registered. /// Storing this enables the Relying Party to reference the credent’al's attestation statement at a later time. /// </summary> public byte[] AttestationObject { get; set; } /// <summary> /// The value of the clientDataJSON attribute when the public key credential source was registered. /// Storing this in combination with the above attestationObject item enables the Relying Party to re-verify the attestation signature at a later time. /// </summary> public byte[] AttestationClientDataJson { get; set; } public List<byte[]> DevicePublicKeys { get; set; } public byte[] UserId { get; set; } public PublicKeyCredentialDescriptor Descriptor { get; set; } public byte[] UserHandle { get; set; } public string AttestationFormat { get; set; } public DateTimeOffset RegDate { get; set; } public Guid AaGuid { get; set; } }
<?php declare(strict_types=1); namespace App\Entity; use App\Repository\PublicKeyCredentialSourceRepository; use DateTimeImmutable; use Doctrine\DBAL\Types\Types; use Doctrine\ORM\Mapping as ORM; use Symfony\Component\Uid\AbstractUid; use Symfony\Component\Uid\Uuid; use Webauthn\PublicKeyCredentialSource as BasePublicKeyCredentialSource; use Webauthn\TrustPath\TrustPath; #[ORM\Table(name: 'pk_credential_sources')] #[ORM\Entity(repositoryClass: PublicKeyCredentialSourceRepository::class)] class PublicKeyCredentialSource extends BasePublicKeyCredentialSource { #[ORM\Column(type: Types::DATETIME_IMMUTABLE)] public readonly DateTimeImmutable $createdAt; #[ORM\Id] #[ORM\Column(type: Types::STRING, length: 255)] #[ORM\GeneratedValue(strategy: 'NONE')] private string $id; public function __construct( string $publicKeyCredentialId, string $type, array $transports, string $attestationType, TrustPath $trustPath, AbstractUid $aaguid, string $credentialPublicKey, string $userHandle, int $counter ) { $this->id = Uuid::v4()->toRfc4122(); $this->createdAt = new DateTimeImmutable(); parent::__construct($publicKeyCredentialId, $type, $transports, $attestationType, $trustPath, $aaguid, $credentialPublicKey, $userHandle, $counter); } public function getId(): string { return $this->id; } }
В следующей таблице представлен обзор библиотек серверов WebAuthn:
Подпишитесь на наш Passkeys Substack, чтобы получать новости.
Поскольку большинство библиотек одинаково мощны и реализуют стандарт WebAuthn, мы рекомендуем следующее дерево решений:
Если вы просто хотите узнать больше о серверах WebAuthn в целом, мы можем дать несколько рекомендаций:
Для еще более глубокого понимания того, как работает WebAuthn на стороне сервера, вы можете прочитать очень подробный раздел "WebAuthn Relying Party Operations" в RFC WebAuthn, который детализирует каждый шаг, необходимый для регистрации новых учетных данных (7.1) и проверки утверждения аутентификации (7.2).
Оцените ваши конкретные требования к ключам доступа и WebAuthn. Прочитайте о параметрах PublicKeyCredentialCreationOptions и PublicKeyCredentialRequestOptions вместе с клиентскими вызовами API WebAuthn navigator.credentials.create() и navigator.credentials.get().
Для всех библиотек серверов WebAuthn вам потребуется предоставить соответствующую структуру базы данных для хранения и доступа к следующей информации:
Крайне важно полностью понимать, какие поля WebAuthn необходимо хранить и где. Обратите особое внимание на то, какое значение вы хотите использовать для идентификатора пользователя (user.id). Также примите во внимание, что происходит, когда пользователь может удалить ключ доступа. Список действительных аутентификаторов, связанных с ключами доступа, можно найти здесь. Дополнительную информацию можно найти здесь.
Определите, на каких устройствах ваши пользователи будут использовать ключи доступа и резервные методы аутентификации. Если вы не уверены, проверьте State of Passkeys для получения последних данных о готовности к работе с ключами доступа. С точки зрения наблюдаемости (observability), храните клиентские сбои WebAuthn и отклонения при проверке сервером как отдельные потоки данных. Кроме того, следует помнить, что для Windows 10 и Linux вам потребуется придумать специальные решения, поскольку эти операционные системы обеспечивают наименьшую (если вообще обеспечивают) поддержку ключей доступа.
Посмотрите, сколько людей действительно используют passkeys.
В настоящее время почти для каждого языка или фреймворка существует хорошо зарекомендовавшая себя библиотека сервера WebAuthn. Сравнение библиотек не показывает явного превосходства определенных реализаций. Скорее вам следует использовать фреймворк или язык программирования, с которым вы лучше всего знакомы. В качестве альтернативы, если вы не хотите реализовывать WebAuthn самостоятельно, вы можете попробовать готовое решение, такое как Corbado. Вы можете попробовать его бесплатно с неограниченным количеством пользователей здесь.
Corbado — это Authentication Intelligence Platform для CIAM-команд, обеспечивающих аутентификацию пользователей в крупных масштабах. Мы показываем то, что не видят логи IDP и общие инструменты аналитики: какие устройства, версии ОС, браузеры и менеджеры учётных данных поддерживают passkey, почему регистрации не превращаются в логины, где сбоит WebAuthn-поток и когда обновление ОС или браузера тихо ломает вход — всё это без замены Okta, Auth0, Ping, Cognito или вашего собственного IDP. Два продукта: Corbado Observe добавляет наблюдаемость для passkey и любых других способов входа. Corbado Connect даёт managed passkey со встроенной аналитикой (рядом с вашим IDP). VicRoads использует passkey для более чем 5 млн пользователей с Corbado (+80 % активации passkey). Поговорить с экспертом по passkey →
Сначала проверьте, существует ли библиотека для вашего конкретного фреймворка, а затем — для вашего языка программирования. Поскольку все перечисленные библиотеки одинаково реализуют стандарт WebAuthn, выбор должен отдавать приоритет знакомству с вашим существующим стеком технологий, а не различиям в функциях между библиотеками.
Как минимум вы должны сохранять учетные данные, пользователей, вызовы (challenges) и аутентификаторы. Обратите пристальное внимание на то, какое значение вы назначаете в качестве идентификатора пользователя (userHandle), и спланируйте сценарии, при которых пользователи могут удалить ключ доступа (passkey) со своего устройства.
Библиотеки серверов WebAuthn обрабатывают самые сложные криптографические операции: генерацию параметров PublicKeyCredentialCreationOptions и PublicKeyCredentialRequestOptions, а также проверцию подписанных вызовов. Сделать это правильно с нуля значительно сложнее, чем использовать проверенную и прошедшую аудит библиотеку, соответствующую стандарту FIDO.
Windows 10 и Linux обеспечивают наименьшую поддержку ключей доступа, поэтому для пользователей этих платформ требуются специальные резервные решения. Мониторинг сбоев WebAuthn на стороне клиента и отклонений проверки сервером как отдельных потоков помогает выявлять проблемы, специфичные для ОС, в производственной среде.
Посмотрите, как Corbado вписывается во внедрение passkeys и текущий стек аутентификации.
Открыть Console
Похожие статьи
Содержание