Spec-Zone.ru › Web APIs

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 байт.

Создание пары ключей и регистрация пользователя

Чтобы проиллюстрировать, как работает процесс создания учётных данных, опишем типичный поток, который происходит, когда пользователь хочет зарегистрировать учётные данные у доверенной стороны:

  1. Сервер доверенной стороны отправляет информацию о пользователе и доверенной стороне в веб-приложение, обрабатывающее процесс регистрации, а также «вызов», используя соответствующий защищённый механизм (например, Fetch или XMLHttpRequest).

    Примечание: Формат обмена информацией между сервером доверенной стороны и веб-приложением зависит от приложения. Рекомендуемым подходом является обмен объектами типа представления JSON для учётных данных и опций учётных данных. В PublicKeyCredential были созданы удобные методы для преобразования из представлений JSON в требуемый формат API аутентификации: parseCreationOptionsFromJSON(), parseRequestOptionsFromJSON() и PublicKeyCredential.toJSON().

  2. Веб-приложение инициирует генерацию новых учётных данных через аутентификатор от имени доверенной стороны с помощью вызова 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, который подписан для обеспечения того, что он не был изменён.

  3. После получения согласия пользователя аутентификатор генерирует пару ключей и возвращает открытый ключ и необязательную подписанную аттестацию веб-приложению. Это предоставляется, когда Promise, возвращённый вызовом create(), выполняется в виде экземпляра объекта PublicKeyCredential (свойство PublicKeyCredential.response содержит информацию об аттестации).

  4. Веб-приложение передаёт PublicKeyCredential на сервер, опять же, с помощью соответствующего механизма.

  5. Сервер сохраняет открытый ключ, связанный с идентификатором пользователя, чтобы запомнить учётные данные для будущей аутентификации. В процессе выполнения ряда проверок, чтобы убедиться, что регистрация была завершена и не подвергалась изменениям. Эти проверки включают:

    1. Проверка того, что вызов совпадает с вызовом, который был отправлен.
    2. Обеспечение того, что домен совпадает с ожидаемым доменом.
    3. Проверка того, что подпись и аттестация используют правильную цепочку сертификатов для конкретной модели аутентификатора, используемого для генерации пары ключей в самом начале.

Предупреждение: Аттестация предоставляет способ для доверенной стороны определить происхождение аутентификатора. Доверенные стороны не должны пытаться поддерживать списки разрешённых аутентификаторов.

Аутентификация пользователя

После регистрации пользователя с помощью WebAuthn, он может авторизоваться (т.е., войти) в сервис. Поток аутентификации похож на поток регистрации, основные отличия заключаются в том, что аутентификация:

  1. Не требует информации о пользователе или доверенной стороне
  2. Создаёт утверждение, используя ранее сгенерированную пару ключей для сервиса, а не пару ключей аутентификатора.

Типичный поток аутентификации выглядит следующим образом:

  1. Доверенная сторона генерирует «вызов» и отправляет его агенту пользователя с помощью соответствующего защищённого механизма вместе со списком учётных данных доверенной стороны и пользователя. Она также может указать, где искать учётные данные, например, в локальном встроенном аутентификаторе или во внешнем аутентификаторе через USB, BLE и т.д.

  2. Браузер запрашивает у аутентификатора подпись вызова посредством вызова 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() передаются аутентификатору для обработки аутентификации.

  3. Если аутентификатор содержит одни из предоставленных учётных данных и может успешно подписать вызов, он возвращает подписанное утверждение веб-приложению после получения согласия пользователя. Это предоставляется, когда Promise, возвращённый вызовом get(), выполняется в виде экземпляра объекта PublicKeyCredential (свойство PublicKeyCredential.response содержит информацию об утверждении).

  4. Веб-приложение передаёт подписанное утверждение серверу доверенной стороны для проверки. Проверки включают:

    1. Использование открытого ключа, сохранённого во время запроса регистрации, для проверки подписи аутентификатором.
    2. Проверка того, что вызов, подписанный аутентификатором, соответствует вызову, сгенерированному сервером.
    3. Проверка того, что идентификатор доверенной стороны соответствует ожидаемому для этого сервиса.
  5. После проверки сервером поток аутентификации считается успешным.

Управление доступом к 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>, необходимо выполнить несколько шагов:

  1. Сайт, встраивающий сайт-получатель, должен предоставить разрешение через атрибут 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() вызывается с другим источником.

  2. Сайт-получатель должен предоставить разрешение на вышеуказанный доступ через заголовок 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 сообщает агенту пользователя использовать существующий набор креденшиалов для аутентификации у стороны, запрашивающей идентификатор.

Примеры

Демо-сайты

  • Демо-сайт Mozilla и его исходный код.
  • Демо-сайт Google и его исходный код.
  • Демо-сайт WebAuthn.io и его исходный код.
  • github.com/webauthn-open-source и его исходный код клиента и исходный код сервера

Пример использования

Примечание: По соображениям безопасности вызовы 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 92
60–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 92
60–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 92
60–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 92
60–92Поддерживаются только USB-токены U2F.
49 13 10.0 Нет
response 67 18
60Поддерживаются только USB-токены U2F.
54 13 70 92
60–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

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API