API аутентификации веб-приложений
Базовая версия Широко доступна *
Эта функция хорошо зарекомендовала себя и работает на многих устройствах и версиях браузеров. Она доступна в браузерах с сентября 2021 года.
* Некоторые части этой функции могут иметь различный уровень поддержки.
Защищённый контекст: Эта функция доступна только в защищённых контекстах (HTTPS), в некоторых или всех поддерживающих браузерах.
API аутентификации веб-приложений (WebAuthn) — это расширение API управления учётными данными, которое позволяет реализовывать надёжную аутентификацию с использованием криптографии с открытым ключом, обеспечивая беспарольную аутентификацию и безопасную многофакторную аутентификацию (MFA) без SMS-сообщений.
Примечание: Passkeys — важный пример использования веб-аутентификации; см. Создать passkey для беспарольной авторизации и Авторизация с помощью passkey через автозаполнение формы для получения подробностей об реализации. Также см. Google Identity > Беспарольная авторизация с passkeys.
Концепции и использование WebAuthn
WebAuthn использует асимметричную (с открытым ключом) криптографию вместо паролей или SMS-сообщений для регистрации, аутентификации и многофакторной аутентификации на веб-сайтах. Это имеет некоторые преимущества:
- Защита от фишинга: Злоумышленник, создающий поддельный веб-сайт входа, не может войти как пользователь, потому что подпись изменяется в зависимости от домена веб-сайта.
- Снижение последствий утечек данных: Разработчикам не нужно хэшировать открытый ключ, и если злоумышленник получает доступ к открытому ключу, используемому для проверки аутентификации, он не сможет выполнить аутентификацию, потому что ему нужен закрытый ключ.
- Устойчивость к атакам на пароли: Некоторые пользователи могут повторно использовать пароли, и злоумышленник может получить пароль пользователя для другого сайта (например, через утечку данных). Кроме того, текстовые пароли гораздо легче взломать, чем цифровую подпись.
Многие веб-сайты уже имеют страницы, которые позволяют пользователям регистрировать новые учётные записи или входить в существующую учётную запись, и WebAuthn используется как замена или расширение для части системы аутентификации. Он расширяет API управления учётными данными, абстрагируя взаимодействие между агентом пользователя и аутентификатором и предоставляя следующие новые возможности:
- Когда
navigator.credentials.create()используется с опциейpublicKey, агент пользователя создаёт новые учётные данные через аутентификатор — для регистрации новой учётной записи или для привязки новой пары асимметричных ключей к существующей учётной записи.- При регистрации новой учётной записи эти учётные данные хранятся на сервере (также известном как сервис или доверенная сторона) и могут быть впоследствии использованы для входа пользователя.
- Пара асимметричных ключей хранится в аутентификаторе, который затем может быть использован для аутентификации пользователя у доверенной стороны, например, во время MFA. Аутентификатор может быть встроен в агента пользователя, в операционную систему, такую как Windows Hello, или это может быть физический токен, например, USB или Bluetooth Security Key.
- Когда
navigator.credentials.get()используется с опциейpublicKey, агент пользователя использует существующий набор учётных данных для аутентификации у доверенной стороны (либо в качестве основного входа, либо для предоставления дополнительного фактора во время MFA, как описано выше).
В своей самой базовой форме и create(), и get() получают очень большое случайное число, называемое «вызовом», от сервера и возвращают подписанный вызов с помощью закрытого ключа обратно на сервер. Это доказывает серверу, что у пользователя есть закрытый ключ, необходимый для аутентификации, не раскрывая никаких секретов по сети.
Примечание: «Вызов» должен быть буфером случайной информации размером не менее 16 байт.
Создание пары ключей и регистрация пользователя
Чтобы проиллюстрировать, как работает процесс создания учётных данных, опишем типичный поток, который происходит, когда пользователь хочет зарегистрировать учётные данные у доверенной стороны:
-
Сервер доверенной стороны отправляет информацию о пользователе и доверенной стороне в веб-приложение, обрабатывающее процесс регистрации, а также «вызов», используя соответствующий защищённый механизм (например, Fetch или XMLHttpRequest).
Примечание: Формат обмена информацией между сервером доверенной стороны и веб-приложением зависит от приложения. Рекомендуемым подходом является обмен объектами типа представления JSON для учётных данных и опций учётных данных. В
PublicKeyCredentialбыли созданы удобные методы для преобразования из представлений JSON в требуемый формат API аутентификации:parseCreationOptionsFromJSON(),parseRequestOptionsFromJSON()иPublicKeyCredential.toJSON(). -
Веб-приложение инициирует генерацию новых учётных данных через аутентификатор от имени доверенной стороны с помощью вызова
navigator.credentials.create(). В этом вызове передаётся опцияpublicKey, определяющая возможности устройства, например, предоставляет ли устройство собственной аутентификации пользователя (например, с биометрией).Типичный вызов
create()может выглядеть следующим образом:let credential = await navigator.credentials.create({ publicKey: { challenge: new Uint8Array([117, 61, 252, 231, 191, 241, ...]), rp: { id: "acme.com", name: "ACME Corporation" }, user: { id: new Uint8Array([79, 252, 83, 72, 214, 7, 89, 26]), name: "jamiedoe", displayName: "Jamie Doe" }, pubKeyCredParams: [ {type: "public-key", alg: -7} ] } });Параметры вызова
create()передаются аутентификатору вместе с хэшем SHA-256, который подписан для обеспечения того, что он не был изменён. -
После получения согласия пользователя аутентификатор генерирует пару ключей и возвращает открытый ключ и необязательную подписанную аттестацию веб-приложению. Это предоставляется, когда
Promise, возвращённый вызовомcreate(), выполняется в виде экземпляра объектаPublicKeyCredential(свойствоPublicKeyCredential.responseсодержит информацию об аттестации). -
Веб-приложение передаёт
PublicKeyCredentialна сервер, опять же, с помощью соответствующего механизма. -
Сервер сохраняет открытый ключ, связанный с идентификатором пользователя, чтобы запомнить учётные данные для будущей аутентификации. В процессе выполнения ряда проверок, чтобы убедиться, что регистрация была завершена и не подвергалась изменениям. Эти проверки включают:
- Проверка того, что вызов совпадает с вызовом, который был отправлен.
- Обеспечение того, что домен совпадает с ожидаемым доменом.
- Проверка того, что подпись и аттестация используют правильную цепочку сертификатов для конкретной модели аутентификатора, используемого для генерации пары ключей в самом начале.
Предупреждение: Аттестация предоставляет способ для доверенной стороны определить происхождение аутентификатора. Доверенные стороны не должны пытаться поддерживать списки разрешённых аутентификаторов.
Аутентификация пользователя
После регистрации пользователя с помощью WebAuthn, он может авторизоваться (т.е., войти) в сервис. Поток аутентификации похож на поток регистрации, основные отличия заключаются в том, что аутентификация:
- Не требует информации о пользователе или доверенной стороне
- Создаёт утверждение, используя ранее сгенерированную пару ключей для сервиса, а не пару ключей аутентификатора.
Типичный поток аутентификации выглядит следующим образом:
-
Доверенная сторона генерирует «вызов» и отправляет его агенту пользователя с помощью соответствующего защищённого механизма вместе со списком учётных данных доверенной стороны и пользователя. Она также может указать, где искать учётные данные, например, в локальном встроенном аутентификаторе или во внешнем аутентификаторе через USB, BLE и т.д.
-
Браузер запрашивает у аутентификатора подпись вызова посредством вызова
navigator.credentials.get(), которому передаются учётные данные в опцииpublicKey.Типичный вызов
get()может выглядеть так:let credential = await navigator.credentials.get({ publicKey: { challenge: new Uint8Array([139, 66, 181, 87, 7, 203, ...]), rpId: "acme.com", allowCredentials: [{ type: "public-key", id: new Uint8Array([64, 66, 25, 78, 168, 226, 174, ...]) }], userVerification: "required", } });Параметры вызова
get()передаются аутентификатору для обработки аутентификации. -
Если аутентификатор содержит одни из предоставленных учётных данных и может успешно подписать вызов, он возвращает подписанное утверждение веб-приложению после получения согласия пользователя. Это предоставляется, когда
Promise, возвращённый вызовомget(), выполняется в виде экземпляра объектаPublicKeyCredential(свойствоPublicKeyCredential.responseсодержит информацию об утверждении). -
Веб-приложение передаёт подписанное утверждение серверу доверенной стороны для проверки. Проверки включают:
- Использование открытого ключа, сохранённого во время запроса регистрации, для проверки подписи аутентификатором.
- Проверка того, что вызов, подписанный аутентификатором, соответствует вызову, сгенерированному сервером.
- Проверка того, что идентификатор доверенной стороны соответствует ожидаемому для этого сервиса.
-
После проверки сервером поток аутентификации считается успешным.
Управление доступом к API
Доступность WebAuthn можно контролировать с помощью Политики разрешений, указав в частности две директивы:
-
publickey-credentials-create: Управляет доступностьюnavigator.credentials.create()с опциейpublicKey. -
publickey-credentials-get: Управляет доступностьюnavigator.credentials.get()с опциейpublicKey.
Обе директивы имеют значение списка разрешенных по умолчанию "self", что означает, что по умолчанию эти методы могут быть использованы в контекстах документов верхнего уровня. Кроме того, get() может использоваться во вложенных контекстах просмотра, загруженных с того же источника, что и документ самого верхнего уровня. get() и create() могут использоваться во вложенных контекстах просмотра, загруженных с разных источников по сравнению с документом самого верхнего уровня (т. е. в междоменных <iframes>), если это разрешено директивами publickey-credentials-get и publickey-credentials-create соответственно. Для междоменных create() вызовов, где разрешение было предоставлено allow= во фрейме, фрейм также должен иметь Временную активацию.
Примечание: Если политика запрещает использование этих методов, возвращаемые ими обещания отклонятся с NotAllowedError DOMException.
Базовый контроль доступа
Если вы хотите разрешить доступ только к определенному поддомену, вы можете указать его так:
Permissions-Policy: publickey-credentials-get=("https://subdomain.example.com")
Permissions-Policy: publickey-credentials-create=("https://subdomain.example.com")
Разрешение вложенных вызовов create и get() во фрейме <iframe>
Если вы хотите аутентифицироваться с помощью get() или create() во фрейме <iframe>, необходимо выполнить несколько шагов:
-
Сайт, встраивающий сайт-получатель, должен предоставить разрешение через атрибут
allow:-
Если используется
get():<iframe src="https://auth.provider.com" allow="publickey-credentials-get *"> </iframe>
-
Если используется
create():<iframe src="https://auth.provider.com" allow="publickey-credentials-create 'self' https://a.auth.provider.com https://b.auth.provider.com"> </iframe>
Фрейм
<iframe>также должен иметь Временную активацию, еслиcreate()вызывается с другим источником.
-
-
Сайт-получатель должен предоставить разрешение на вышеуказанный доступ через заголовок
Permissions-Policy:Permissions-Policy: publickey-credentials-get=* Permissions-Policy: publickey-credentials-create=*
Или, чтобы разрешить встраивание сайта-получателя только в конкретный URL во фрейме
<iframe>:Permissions-Policy: publickey-credentials-get=("https://subdomain.example.com") Permissions-Policy: publickey-credentials-create=("https://*.auth.provider.com")
Интерфейсы
AuthenticatorAssertionResponse-
Предоставляет доказательство сервису, что у аутентификатора есть необходимая пара ключей для успешной обработки запроса на аутентификацию, инициированного вызовом
CredentialsContainer.get(). Доступно в свойствеresponseэкземпляраPublicKeyCredential, полученного при выполненииget()Promise. AuthenticatorAttestationResponse-
Результат регистрации идентификатора WebAuthn (т. е. вызова
CredentialsContainer.create()). Он содержит информацию о креденшиале, необходимую серверу для выполнения утверждений WebAuthn, такую как его идентификатор креденшиала и открытый ключ. Доступно в свойствеresponseэкземпляраPublicKeyCredential, полученного при выполненииcreate()Promise. AuthenticatorResponse-
Базовый интерфейс для
AuthenticatorAttestationResponseиAuthenticatorAssertionResponse. PublicKeyCredential-
Предоставляет информацию об открытой/закрытой паре ключей, представляющей собой идентификатор для входа в службу с помощью не подделываемой и устойчивой к взлому асимметричной пары ключей вместо пароля. Получается при выполнении
Promise, возвращаемого вызовомcreate()илиget().
Расширения других интерфейсов
-
CredentialsContainer.create(), опцияpublicKey -
Вызов
create()с опциейpublicKeyинициирует создание новых асимметричных ключевых креденшиалов через аутентификатор, как описано выше. -
CredentialsContainer.get(), опцияpublicKey -
Вызов
get()с опциейpublicKeyсообщает агенту пользователя использовать существующий набор креденшиалов для аутентификации у стороны, запрашивающей идентификатор.
Примеры
Демо-сайты
Пример использования
Примечание: По соображениям безопасности вызовы API аутентификации Web (create() и get()) отменяются, если окно браузера теряет фокус во время ожидания вызова.
// sample arguments for registration
const createCredentialDefaultArgs = {
publicKey: {
// Relying Party (a.k.a. - Service):
rp: {
name: "Acme",
},
// User:
user: {
id: new Uint8Array(16),
name: "carina.p.anand@example.com",
displayName: "Carina P. Anand",
},
pubKeyCredParams: [
{
type: "public-key",
alg: -7,
},
],
attestation: "direct",
timeout: 60000,
challenge: new Uint8Array([
// must be a cryptographically random number sent from a server
0x8c, 0x0a, 0x26, 0xff, 0x22, 0x91, 0xc1, 0xe9, 0xb9, 0x4e, 0x2e, 0x17,
0x1a, 0x98, 0x6a, 0x73, 0x71, 0x9d, 0x43, 0x48, 0xd5, 0xa7, 0x6a, 0x15,
0x7e, 0x38, 0x94, 0x52, 0x77, 0x97, 0x0f, 0xef,
]).buffer,
},
};
// sample arguments for login
const getCredentialDefaultArgs = {
publicKey: {
timeout: 60000,
// allowCredentials: [newCredential] // see below
challenge: new Uint8Array([
// must be a cryptographically random number sent from a server
0x79, 0x50, 0x68, 0x71, 0xda, 0xee, 0xee, 0xb9, 0x94, 0xc3, 0xc2, 0x15,
0x67, 0x65, 0x26, 0x22, 0xe3, 0xf3, 0xab, 0x3b, 0x78, 0x2e, 0xd5, 0x6f,
0x81, 0x26, 0xe2, 0xa6, 0x01, 0x7d, 0x74, 0x50,
]).buffer,
},
};
// register / create a new credential
navigator.credentials
.create(createCredentialDefaultArgs)
.then((cred) => {
console.log("NEW CREDENTIAL", cred);
// normally the credential IDs available for an account would come from a server
// but we can just copy them from above…
const idList = [
{
id: cred.rawId,
transports: ["usb", "nfc", "ble"],
type: "public-key",
},
];
getCredentialDefaultArgs.publicKey.allowCredentials = idList;
return navigator.credentials.get(getCredentialDefaultArgs);
})
.then((assertion) => {
console.log("ASSERTION", assertion);
})
.catch((err) => {
console.log("ERROR", err);
});
Спецификации
| Спецификация |
|---|
| Веб-аутентификация: API для доступа к креденшиалам открытого ключа - Уровень 3 # iface-pkcredential |
Совместимость с браузерами
| Рабочий стол | Мобильные устройства | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|
| Chrome | Edge | Firefox | Opera | Safari | Chrome Android | Firefox for Android | Opera Android | Safari на iOS | Samsung Internet | WebView Android | |
Web_Authentication_API |
67 | 18 | 60Поддерживаются только USB-токены U2F. |
54 | 13 | 70 | 9260–92Поддерживаются только USB-токены U2F. |
49 | 13 | 10.0 | Нет |
authenticatorAttachment |
98 | 98 | 120 | 84 | 15.5 | 98 | 120 | 68 | 15.5 | 18.0 | Нет |
getClientCapabilities_static |
133 | 133 | 135 | Нет | 17.4 | 133 | 135 | Нет | 17.4 | Нет | Нет |
getClientExtensionResults |
67 | 18 | 60Поддерживаются только USB-токены U2F. |
54 | 13 | 70 | 9260–92Поддерживаются только USB-токены U2F. |
49 | 13 | 10.0 | Нет |
isConditionalMediationAvailable_static |
108 | 108 | 119 | 94 | 16 | 108 | 119 | 73 | 16 | 21.0 | Нет |
isUserVerifyingPlatformAuthenticatorAvailable_static |
67 | 18 | 60Поддерживаются только USB-токены U2F. |
54 | 13 | 70 | 9260–92Поддерживаются только USB-токены U2F. |
49 | 13 | 10.0 | Нет |
parseCreationOptionsFromJSON_static |
129 | 129 | 119 | 115 | Нет | 129 | 119 | 86 | Нет | Нет | Нет |
parseRequestOptionsFromJSON_static |
129 | 129 | 119 | 115 | Нет | 129 | 119 | 86 | Нет | Нет | Нет |
rawId |
67 | 18 | 60Поддерживаются только USB-токены U2F. |
54 | 13 | 70 | 9260–92Поддерживаются только USB-токены U2F. |
49 | 13 | 10.0 | Нет |
response |
67 | 18 | 60Поддерживаются только USB-токены U2F. |
54 | 13 | 70 | 9260–92Поддерживаются только USB-токены U2F. |
49 | 13 | 10.0 | Нет |
signalAllAcceptedCredentials_static |
132 | Нет | Нет | 117 | Нет | Нет | Нет | Нет | Нет | Нет | Нет |
signalCurrentUserDetails_static |
132 | Нет | Нет | 117 | Нет | Нет | Нет | Нет | Нет | Нет | Нет |
signalUnknownCredential_static |
132 | Нет | Нет | 117 | Нет | Нет | Нет | Нет | Нет | Нет | Нет |
toJSON |
129 | 129 | 119 | 115 | Нет | 129 | 119 | 86 | Нет | Нет | Нет |
© 2005–2024 MDN contributors.
Licensed under the Creative Commons Attribution-ShareAlike License v2.5 or later.
https://developer.mozilla.org/en-US/docs/Web/API/Web_Authentication_API