Войдите в систему с помощью пароля через автозаполнение формы.

Создайте систему авторизации, которая использует пароли, но при этом поддерживает пользователей, использующих существующие пароли.

В этом руководстве объясняется, как использовать автозаполнение форм, чтобы пользователи могли входить в систему с помощью паролей и ключей доступа одновременно. Использование автозаполнения форм создает единый процесс входа в систему, упрощая переход от паролей к более безопасному и удобному методу аутентификации с помощью ключей доступа.

Узнайте, как реализовать условный пользовательский интерфейс WebAuthn для поддержки пользователей, использующих как пароль, так и пароль, с минимальными неудобствами в существующих формах входа в систему.

Зачем использовать автозаполнение форм для входа в систему с помощью пароля?

Пароли позволяют пользователям входить на веб-сайты, используя отпечаток пальца, распознавание лица или PIN-код устройства.

Если бы у всех пользователей были пароли, процесс аутентификации мог бы представлять собой единую кнопку входа. Нажатие на эту кнопку позволило бы пользователю напрямую подтвердить учетную запись с помощью блокировки экрана и войти в систему.

Однако переход от паролей к ключам доступа сопряжен с трудностями. В этот период веб-сайты должны поддерживать как пользователей паролей, так и пользователей ключей доступа. Ожидание от пользователей запоминания того, какие сайты используют ключи доступа, и просьба выбрать способ входа заранее создают неудовлетворительный пользовательский опыт.

Пароли — это тоже новая технология, и объяснить их назначение внятно может быть сложно. Использование привычного интерфейса автозаполнения помогает решить как проблему перехода, так и необходимость ознакомления пользователя с технологией.

Используйте условный пользовательский интерфейс.

Для эффективной поддержки пользователей, использующих как пароль, так и пароль, включите ключи доступа в подсказки автозаполнения вашей формы. Этот подход использует условный пользовательский интерфейс , функцию стандарта WebAuthn .

Пример выбора пароля с помощью автозаполнения формы.

Когда пользователь фокусируется на поле ввода имени пользователя, появляется диалоговое окно автозаполнения, предлагающее сохраненные ключи доступа наряду с сохраненными паролями. Пользователь может выбрать либо ключ доступа, либо пароль и продолжить вход в систему, используя блокировку экрана устройства, если он выберет ключ доступа.

Это позволяет пользователям входить на ваш сайт с помощью существующей формы авторизации, но с дополнительным преимуществом безопасности в виде паролей, если они у них есть.

Как работает аутентификация по паролю

Для аутентификации с помощью пароля используется API WebAuthn .

В поток аутентификации с помощью пароля входят четыре компонента:

  • Бэкенд : хранит данные учетных записей пользователей, включая открытый ключ.
  • Фронтенд : взаимодействует с браузером и получает необходимые данные с бэкэнда.
  • Браузер : Выполняет ваш JavaScript и взаимодействует с API WebAuthn.
  • Поставщик ключа доступа : создает и хранит ключ доступа. Обычно это менеджер паролей, например Google Password Manager, или ключ безопасности.
Схема аутентификации с помощью пароля, демонстрирующая взаимодействие между интерфейсом, бэкэндом, браузером и поставщиком пароля.
Полный процесс аутентификации с использованием пароля.

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

  1. Пользователь переходит на страницу входа в систему, и фронтенд запрашивает у бэкенда подтверждение подлинности.
  2. Серверная часть генерирует и возвращает запрос WebAuthn, связанный с учетной записью пользователя.
  3. Фронтенд вызывает метод navigator.credentials.get() с запросом на аутентификацию для запуска аутентификации через браузер .
  4. Браузер , взаимодействуя с поставщиком паролей , предлагает пользователю выбрать пароль (часто с помощью диалогового окна автозаполнения, запускаемого при фокусировке на поле входа в систему) и подтвердить свою личность с помощью блокировки экрана устройства или биометрических данных.
  5. После успешной проверки пользователя поставщик ключей подписывает запрос, и браузер возвращает полученные учетные данные открытого ключа (включая подпись) на фронтенд .
  6. Фронтенд отправляет эти учетные данные на бэкенд .
  7. Серверная часть проверяет подпись учетных данных по сохраненному открытому ключу пользователя. Если проверка проходит успешно, серверная часть выполняет вход пользователя в систему.

Аутентификация с помощью пароля через автозаполнение формы.

Для инициализации аутентификации по паролю с использованием автозаполнения формы выполните условный вызов WebAuthn get при загрузке страницы входа. Этот вызов navigator.credentials.get() включает опцию mediation: 'conditional' .
Условный запрос к API navigator.credentials.get() WebAuthn не отображает пользовательский интерфейс немедленно. Вместо этого он ожидает в состоянии ожидания, пока пользователь не взаимодействует с запросом автозаполнения в поле имени пользователя. Если пользователь выбирает пароль, браузер разрешает ожидающее обещание, передавая учетные данные для входа пользователя, минуя традиционную отправку формы. Если пользователь выбирает пароль, обещание не разрешается, и продолжается стандартный процесс входа по паролю. После этого вход пользователя в систему становится обязанностью страницы.

Аннотировать поле ввода формы

Чтобы включить автозаполнение пароля, добавьте атрибут autocomplete к полю input имени пользователя в вашей форме. Укажите username и webauthn в виде значений, разделенных пробелами.

<input type="text" name="username" autocomplete="username webauthn" autofocus>

Добавление autofocus к этому полю автоматически запускает запрос автозаполнения при загрузке страницы, немедленно отображая доступные пароли и ключи доступа.

Обнаружение признаков

Перед выполнением условного вызова API WebAuthn проверьте следующее:

  • Браузер поддерживает WebAuthn с использованием PublicKeyCredential .

Browser Support

  • Chrome: 67.
  • Край: 18.
  • Firefox: 60.
  • Сафари: 13.

Source

  • Браузер поддерживает определение возможностей с помощью PublicKeyCredential.getClientCapabilities() .

Browser Support

  • Chrome: 133.
  • Edge: 133.
  • Firefox: 135.
  • Сафари: 17.4.

Source

Следующий фрагмент кода показывает, как проверить, поддерживает ли браузер эти функции:

if (window.PublicKeyCredential && PublicKeyCredential.getClientCapabilities) {
  const capabilities = await PublicKeyCredential.getClientCapabilities();
  // Check if conditional mediation is available.  
  if (capabilities.conditionalGet === true) {
    // The browser supports conditional mediation.
  }
}

Получение информации из бэкэнда

Для инициализации вызова navigator.credentials.get() ваш бэкэнд должен предоставить фронтенду несколько параметров. Эти параметры обычно извлекаются в виде JSON-объекта из конечной точки на вашем сервере.

Ключевые свойства объекта параметров включают в себя:

  • challenge : Сгенерированный сервером запрос в ArrayBuffer (обычно закодированный в Base64URL для передачи в формате JSON). Это необходимо для предотвращения атак повторного воспроизведения. Ваш сервер должен генерировать новый запрос для каждой попытки входа в систему и аннулировать его через короткое время или в случае неудачной попытки.
  • allowCredentials : Массив дескрипторов учетных данных. Передайте пустой массив . Это заставит браузер вывести список всех учетных данных для указанного rpId .
  • userVerification : Указывает ваши предпочтения относительно проверки пользователя, например, обязательной блокировки экрана устройства. Значение по умолчанию и рекомендуемое значение — "preferred" . Возможные значения:

    • "required" : Проверка пользователя должна быть выполнена аутентификатором (например, с помощью PIN-кода или биометрии). Операция завершится неудачей, если проверка не может быть выполнена.
    • "preferred" : Аутентификатор пытается подтвердить личность пользователя, но операция может быть успешно выполнена и без этого.
    • "discouraged" : Аутентификатору следует по возможности избегать проверки пользователя.
  • rpId : Идентификатор вашей зависимой стороны, как правило, домен вашего веб-сайта (например, example.com ). Это значение должно точно совпадать с rp.id , использованным при создании учетных данных.

Ваш сервер должен создать этот объект параметров. Значения ArrayBuffer (например, значение challenge ) должны быть закодированы в Base64URL для передачи в формате JSON. На стороне клиента, после разбора JSON, используйте PublicKeyCredential.parseRequestOptionsFromJSON() для преобразования объекта (включая декодирование строк Base64URL) в формат, ожидаемый navigator.credentials.get() .

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

// Fetch an encoded PubicKeyCredentialRequestOptions from the server.
const _options = await fetch('/webauthn/signinRequest');

// Deserialize and decode the PublicKeyCredentialRequestOptions.
const decoded_options = JSON.parse(_options);
const options = PublicKeyCredential.parseRequestOptionsFromJSON(decoded_options);
...

Для аутентификации пользователя вызовите API WebAuthn с флагом conditional .

После того, как вы подготовите объект publicKeyCredentialRequestOptions (в приведенном ниже примере кода он называется options ), вызовите метод navigator.credentials.get() для запуска условной аутентификации с использованием пароля.

// To abort a WebAuthn call, instantiate an AbortController.
const abortController = new AbortController();

// Invoke WebAuthn to authenticate with a passkey.
const credential = await navigator.credentials.get({
  publicKey: options,
  signal: abortController.signal,
  // Specify 'conditional' to activate conditional UI
  mediation: 'conditional'
});

Основные параметры для этого звонка:

  • publicKey : Это должен быть объект publicKeyCredentialRequestOptions (в примере он называется options ), который вы получили с сервера и обработали на предыдущем шаге.
  • signal : Передача сигнала из AbortController (например, abortController.signal ) позволяет программно отменить запрос get() . Это полезно, когда вы хотите вызвать другой вызов WebAuthn.
  • mediation: 'conditional' : Это важнейший флаг, который делает вызов WebAuthn условным. Он указывает браузеру ожидать взаимодействия пользователя с запросом автозаполнения, а не сразу показывать модальное диалоговое окно.

Отправьте полученные учетные данные открытого ключа на сервер RP.

Если пользователь выбирает пароль и успешно подтверждает свою личность (например, используя блокировку экрана устройства), выполняется промис navigator.credentials.get() . Это возвращает объект PublicKeyCredential вашему фронтенду.

Промис может быть отклонен по нескольким причинам. Вам следует обрабатывать эти ошибки в своем коде, проверяя свойство name объекта Error :

  • NotAllowedError : Пользователь отменил операцию или не был выбран пароль.
  • AbortError : Операция была прервана, возможно, из-за использования AbortController в вашем коде.
  • Другие исключения: Произошла непредвиденная ошибка. Браузер обычно отображает пользователю диалоговое окно с сообщением об ошибке.

Объект PublicKeyCredential содержит несколько свойств. Ключевые свойства, имеющие отношение к аутентификации, включают:

  • id : Закодированный в base64url идентификатор учетных данных аутентифицированного пароля.
  • rawId : Версия идентификатора учетных данных в формате ArrayBuffer.
  • response.clientDataJSON : ArrayBuffer с данными клиента. Это поле содержит такую ​​информацию, как запрос и источник, который должен проверить ваш сервер.
  • response.authenticatorData : ArrayBuffer, содержащий данные аутентификатора. Это поле включает такую ​​информацию, как идентификатор RP.
  • response.signature : Объект ArrayBuffer, содержащий подпись. Это значение является основой учетных данных, и ваш сервер должен проверить эту подпись, используя сохраненный открытый ключ для этих учетных данных.
  • response.userHandle : Объект ArrayBuffer, содержащий идентификатор пользователя, предоставленный при регистрации пароля.
  • authenticatorAttachment : Указывает, является ли аутентификатор частью клиентского устройства ( platform ) или внешним ( cross-platform ). cross-platform подключение может произойти, если пользователь вошел в систему с помощью телефона . В таких случаях рекомендуется предложить ему создать ключ доступа на текущем устройстве для удобства в будущем.
  • type : В этом поле всегда устанавливается значение "public-key" .

Чтобы отправить этот объект PublicKeyCredential на ваш бэкэнд, сначала вызовите метод .toJSON() . Этот метод создает JSON-сериализуемую версию учетных данных, которая корректно обрабатывает преобразование свойств ArrayBuffer (таких как rawId , clientDataJSON , authenticatorData , signature и userHandle ) в строки, закодированные в Base64URL. Затем используйте JSON.stringify() для преобразования этого объекта в строку и отправьте ее в теле запроса на сервер.

...
// Encode and serialize the PublicKeyCredential.
const _result = credential.toJSON();
const result = JSON.stringify(_result);

// Encode and send the credential to the server for verification.  
const response = await fetch('/webauthn/signinResponse', {
  method: 'post',
  credentials: 'same-origin',
  body: result
});

Проверьте подпись.

Когда ваш бэкэнд-сервер получает учетные данные открытого ключа, он должен проверить их подлинность. Это включает в себя:

  1. Анализ данных учетных данных.
  2. Поиск сохраненного открытого ключа, связанного с id учетных данных.
  3. Проверка полученной signature на соответствие сохраненному открытому ключу.
  4. Проверка других данных, таких как суть проблемы и ее происхождение.

Мы рекомендуем использовать серверную библиотеку FIDO/WebAuthn для безопасной обработки этих криптографических операций. Библиотеки с открытым исходным кодом можно найти в репозитории awesome-webauthn на GitHub .

Если подпись и все остальные утверждения верны, сервер может выполнить вход пользователя в систему. Подробные шаги проверки на стороне сервера см. в разделе «Аутентификация с помощью пароля на стороне сервера».

Сообщите, если соответствующие учетные данные не найдены на бэкэнде.

Если ваш бэкэнд-сервер не может найти учетные данные с соответствующим идентификатором во время входа в систему, возможно, пользователь ранее удалил этот пароль с вашего сервера, но не у своего поставщика паролей. Это несоответствие может привести к путанице в работе пользователя, если поставщик паролей продолжает предлагать пароль, который больше не работает с вашим сайтом. Чтобы исправить это, следует сообщить поставщику паролей о необходимости удалить "осиротевший" пароль.

Вы можете использовать метод PublicKeyCredential.signalUnknownCredential() , входящий в состав API Webauthn Signal , чтобы сообщить поставщику ключей доступа о том, что указанные учетные данные были удалены или не существуют. Вызовите этот статический метод на стороне клиента, если ваш сервер указывает (например, с помощью определенного кода состояния HTTP, такого как 404), что представленный идентификатор учетных данных неизвестен. Передайте этому методу идентификатор поставщика ключей доступа и неизвестный идентификатор учетных данных. Поставщик ключей доступа, если он поддерживает сигнал, должен удалить ключ доступа.

// Detect authentication failure due to lack of the credential
if (response.status === 404) {
  // Feature detection
  if (PublicKeyCredential.signalUnknownCredential) {
    await PublicKeyCredential.signalUnknownCredential({
      rpId: "example.com",
      credentialId: "vI0qOggiE3OT01ZRWBYz5l4MEgU0c7PmAA" // base64url encoded credential ID
    });
  } else {
    // Encourage the user to delete the passkey from the password manager nevertheless.
    ...
  }
}

После аутентификации

В зависимости от способа входа пользователя в систему мы предлагаем различные варианты действий.

Если пользователь вошел в систему без пароля

Если пользователь вошел на ваш сайт без пароля, возможно, у него нет зарегистрированного пароля для этой учетной записи или на его текущем устройстве. Это подходящий момент, чтобы побудить пользователя создать пароль. Рассмотрите следующие подходы:

  • Превратите пароли в пароли-ключи : используйте условное создание (conditional create) — функцию WebAuthn, которая позволяет браузеру автоматически создавать пароль-ключ для пользователя после успешного входа в систему с помощью пароля. Это может значительно повысить уровень использования паролей-ключей, упростив процесс их создания. Узнайте, как это работает и как это реализовать, на странице «Помогите пользователям более легко использовать пароли-ключи».
  • Запрос на создание пароля вручную : Поощряйте пользователей к созданию пароля. Это может быть эффективно после завершения пользователем более сложного процесса входа в систему, например, многофакторной аутентификации (МФА). Однако избегайте чрезмерного количества запросов, которые могут мешать пользовательскому опыту.

Чтобы узнать, как побудить пользователей создать пароль и освоить другие передовые методы, ознакомьтесь с примерами в разделе «Сообщение пользователям о паролях» .

Если пользователь вошел в систему с помощью пароля

После успешного входа пользователя в систему с помощью пароля у вас есть несколько возможностей для дальнейшего улучшения его пользовательского опыта и поддержания стабильности учетной записи.

Рекомендуется создавать новый пароль после аутентификации на разных устройствах.

Если пользователь входит в систему с помощью пароля, используя механизм межплатформенного доступа (например, сканируя QR-код своим телефоном), то использованный им пароль может не храниться локально на устройстве, на котором он входит в систему. Это может произойти в следующих случаях:

  • У них есть пароль, но он предоставляется поставщиком паролей, который не поддерживает операционную систему или браузер, используемый для входа в систему.
  • Они потеряли доступ к поставщику ключей доступа на устройстве для входа в систему, но ключ доступа по-прежнему доступен на другом устройстве.

В этой ситуации рекомендуется предложить пользователю создать новый пароль на текущем устройстве. Это позволит избежать повторного входа в систему с разных устройств в будущем. Чтобы определить, вошел ли пользователь в систему с помощью пароля, совместимого с другими устройствами, проверьте свойство authenticatorAttachment учетных данных. Если его значение равно "cross-platform" , это указывает на аутентификацию с разных устройств. В этом случае объясните удобство создания нового пароля и проведите пользователя через процесс его создания.

Синхронизируйте данные пароля с поставщиком услуг, используя сигналы.

Для обеспечения согласованности и улучшения пользовательского опыта ваша проверяющая сторона (RP) может использовать API сигналов WebAuthn для передачи обновлений учетных данных и информации о пользователе поставщику ключей доступа.

Например, чтобы список паролей пользователей, предоставляемый поставщиком ключей, оставался актуальным, необходимо синхронизировать учетные данные на бэкэнде. Можно также сообщить о том, что пароль больше не существует , чтобы поставщики ключей могли удалить ненужные ключи.

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

Чтобы узнать больше о передовых методах обеспечения согласованности паролей, см. раздел «Обеспечение согласованности паролей с учетными данными на вашем сервере с помощью Signal API» .

Не просите второй фактор

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

Контрольный список

  • Предоставьте пользователям возможность входить в систему с помощью пароля через функцию автозаполнения форм.
  • Сигнал, если соответствующие учетные данные для ключа доступа не найдены на серверной части.
  • Предложите пользователям создать пароль вручную, если они еще этого не сделали после входа в систему.
  • Автоматическое создание пароля (условное создание) после входа пользователя в систему с помощью пароля (и второго фактора аутентификации).
  • Если пользователь вошел в систему с помощью пароля, используемого на разных устройствах, будет предложено создать локальный пароль.
  • После входа в систему или при внесении изменений, передайте поставщику список доступных паролей и обновленные данные пользователя (имя пользователя, отображаемое имя).

Ресурсы