Создайте пароль для входа в систему без пароля

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

Опубликовано: 12 октября 2022 г., Последнее обновление: 9 апреля 2026 г.

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

Пароли синхронизируются между устройствами с помощью таких сервисов, как Google Password Manager и iCloud Keychain.

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

Как создается пароль

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

Вы можете попросить пользователей создать пароль в одной из следующих ситуаций:

  • Во время или после регистрации.
  • После входа в систему.
  • После входа в систему с использованием пароля с другого устройства (то есть, authenticatorAttachment является cross-platform ).
  • На специальной странице пользователи могут управлять своими паролями.

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

Процесс регистрации пароля состоит из четырех компонентов:

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

Перед созданием пароля убедитесь, что система соответствует следующим требованиям:

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

  • Фронтенд и бэкенд могут безопасно обмениваться учетными данными.

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

В следующих разделах мы покажем вам, как проверить большинство из них.

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

  1. Система запускает процесс создания пароля, когда пользователь инициирует соответствующее действие (например, нажимает кнопку «Создать пароль» на странице управления паролями или после завершения регистрации).
  2. Фронтенд запрашивает у бэкенда необходимые учетные данные, включая информацию о пользователе, запрос подтверждения и идентификаторы учетных данных для предотвращения дублирования.
  3. Фронтенд вызывает метод navigator.credentials.create() , чтобы запросить у поставщика ключей доступа устройства генерацию ключа доступа с использованием информации из бэкэнда. Обратите внимание, что этот вызов возвращает промис.
  4. Устройство пользователя аутентифицирует его с помощью биометрического метода, PIN-кода или графического ключа для создания пароля.
  5. Поставщик ключей доступа создает ключ доступа и возвращает на фронтенд учетные данные в виде открытого ключа, тем самым выполняя обещание.
  6. Фронтенд отправляет сгенерированные учетные данные открытого ключа на бэкенд.
  7. В бэкэнде хранится открытый ключ и другие важные данные для будущей аутентификации.
  8. Серверная часть уведомляет пользователя (например, по электронной почте) о необходимости подтвердить создание пароля и выявить потенциальный несанкционированный доступ.

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

Совместимость

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

Создать новый пароль

Для создания нового пароля интерфейс пользователя должен выполнить следующие действия:

  1. Проверьте совместимость.
  2. Получить информацию из бэкэнда.
  3. Для создания пароля используйте API WebAuth.
  4. Отправьте полученный открытый ключ на серверную часть.
  5. Сохраните учетные данные.

В следующих разделах показано, как это можно сделать.

Проверьте совместимость.

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

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

Browser Support

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

Source

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

Browser Support

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

Source

  • Браузер поддерживает условный пользовательский интерфейс WebAuthn с помощью conditionalGet .

  • Устройство поддерживает платформенный аутентификатор (может создать ключ доступа и выполнить аутентификацию на устройстве) с помощью passkeyPlatformAuthenticator .

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

if (window.PublicKeyCredential && PublicKeyCredential.getClientCapabilities) {
  const capabilities = await PublicKeyCredential.getClientCapabilities();
  if (capabilities.conditionalGet === true &&
      capabilities.passkeyPlatformAuthenticator === true) {
    // The browser supports passkeys and the conditional UI.
  }
}

В этом примере кнопка «Создать новый пароль» должна отображаться только в том случае, если выполнены все условия.

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

Когда пользователь нажимает кнопку, получите необходимую информацию из бэкэнда, чтобы вызвать метод navigator.credentials.create() .

Приведённый ниже фрагмент кода демонстрирует JSON-объект, содержащий необходимую информацию для вызова метода navigator.credentials.create() :

// Example `PublicKeyCredentialCreationOptions` contents
{
  challenge: *****,
  rp: {
    name: "Example",
    id: "example.com",
  },
  user: {
    id: *****,
    name: "john78",
    displayName: "John",
  },
  pubKeyCredParams: [{
    alg: -7, type: "public-key"
  },{
    alg: -257, type: "public-key"
  }],
  excludeCredentials: [{
    id: *****,
    type: 'public-key',
    transports: ['internal'],
  }],
  authenticatorSelection: {
    authenticatorAttachment: "platform",
    requireResidentKey: true,
  }
}

В объекте пары ключ-значение содержат следующую информацию:

  • challenge : Сгенерированное сервером задание в формате ArrayBuffer для данной регистрации.
  • rp.id : Идентификатор проверяющей стороны (RP ID) , домен и веб-сайт могут указывать либо на свой домен, либо на регистрируемый суффикс. Например, если источником RP является https://login.example.com:1337 , то RP ID может быть либо login.example.com , либо example.com . Если RP ID указан как example.com , пользователь может пройти аутентификацию на login.example.com или на любом из поддоменов example.com . Дополнительную информацию см. в разделе « Разрешить повторное использование ключей доступа на ваших сайтах с помощью запросов от связанных источников» .
  • rp.name : Имя проверяющей стороны (RP). Этот параметр устарел в WebAuthn L3, но включен для обеспечения совместимости.
  • user.id : Уникальный идентификатор пользователя в ArrayBuffer, генерируемый при создании учетной записи. Он должен быть постоянным, в отличие от имени пользователя, которое может быть изменено. Идентификатор пользователя идентифицирует учетную запись, но не должен содержать никакой личной информации (PII) . Вероятно, у вас уже есть идентификатор пользователя в вашей системе, но при необходимости создайте отдельный идентификатор специально для паролей, чтобы он не содержал никакой личной информации.
  • user.name : Уникальный идентификатор учетной записи, который пользователь сможет распознать, например, адрес электронной почты или имя пользователя. Он будет отображаться в окне выбора учетной записи.
  • user.displayName : Обязательное, более удобное для пользователя имя для учетной записи. Оно не обязательно должно быть уникальным и может быть именем, выбранным пользователем. Если на вашем сайте нет подходящего значения для включения сюда, передайте пустую строку. В зависимости от браузера это может отображаться в окне выбора учетной записи.
  • pubKeyCredParams : Указывает поддерживаемые алгоритмы открытого ключа (RP). Рекомендуется установить значение [{alg: -7, type: "public-key"},{alg: -257, type: "public-key"}] . Это обеспечивает поддержку ECDSA с P-256 и RSA PKCS#1, а поддержка этих алгоритмов гарантирует полное покрытие.
  • excludeCredentials : Список уже зарегистрированных идентификаторов учетных данных. Предотвращает двойную регистрацию одного и того же устройства, предоставляя список уже зарегистрированных идентификаторов учетных данных . Член transports , если он предоставлен, должен содержать результат вызова getTransports() во время регистрации каждой учетной записи.
  • authenticatorSelection.authenticatorAttachment : Установите значение "platform" вместе с hint: ['client-device'] если создание этого ключа доступа является обновлением пароля, например, в рамках повышения квалификации после входа в систему. "platform" указывает, что RP хочет использовать платформенный аутентификатор (аутентификатор, встроенный в платформенное устройство), который не запрашивает, например, вставку USB-ключа безопасности. У пользователя есть более простой способ создания ключа доступа.
  • authenticatorSelection.requireResidentKey : Установите значение true в качестве логического параметра. Обнаруживаемые учетные данные (резидентный ключ) хранят информацию о пользователе в ключе доступа и позволяют пользователям выбирать учетную запись при аутентификации.
  • authenticatorSelection.userVerification : Указывает, является ли проверка пользователя с помощью блокировки экрана устройства "required" , "preferred" или "discouraged" . По умолчанию установлено значение "preferred" , что означает, что аутентификатор может пропустить проверку пользователя. Установите значение "preferred" или опустите это свойство.

Мы рекомендуем создать объект на сервере, закодировав ArrayBuffer с помощью Base64URL и получив его с фронтенда. Таким образом, вы сможете декодировать полезную нагрузку с помощью PublicKeyCredential.parseCreationOptionsFromJSON() и передать её напрямую в navigator.credentials.create() .

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

// Fetch an encoded `PubicKeyCredentialCreationOptions` from the server.
const _options = await fetch('/webauthn/registerRequest');

// Deserialize and decode the `PublicKeyCredentialCreationOptions`.
const decoded_options = JSON.parse(_options);
const options = PublicKeyCredential.parseCreationOptionsFromJSON(decoded_options);
...

Воспользуйтесь API WebAuthn для создания ключа аутентификации.

Для создания нового пароля вызовите метод navigator.credentials.create() . API возвращает промис, ожидающий взаимодействия пользователя с отображением модального диалога.

Browser Support

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

Source

// Invoke WebAuthn to create a passkey.
const credential = await navigator.credentials.create({
  publicKey: options
});

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

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

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

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

Объект учетных данных открытого ключа содержит следующие свойства:

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

Закодируйте объект с помощью метода .toJSON() , сериализуйте его с помощью 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/registerResponse', {
  method: 'post',
  credentials: 'same-origin',
  body: result
});
...

Сохраните учетные данные

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

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

Ниже приведён список рекомендуемых объектов недвижимости для сохранения:

  • Идентификатор учетных данных : Идентификатор учетных данных, возвращаемый вместе с учетными данными открытого ключа.
  • Имя учетных данных : Имя учетных данных. Назовите его в соответствии с именем поставщика ключей доступа, который был создан, что можно определить по AAGUID .
  • Идентификатор пользователя : Идентификатор пользователя, использованный для создания пароля.
  • Открытый ключ : Открытый ключ, возвращаемый вместе с учетными данными открытого ключа. Он необходим для проверки утверждения пароля.
  • Дата и время создания : Запишите дату и время создания пароля. Это полезно для идентификации пароля.
  • Дата и время последнего использования : Записывает последнюю дату и время, когда пользователь использовал пароль для входа в систему. Это полезно для определения того, какой пароль пользователь использовал (или не использовал).
  • AAGUID : Уникальный идентификатор поставщика пароля.
  • Флаг «Возможность резервного копирования» : true, если устройство подходит для синхронизации паролей. Эта информация помогает пользователям идентифицировать синхронизируемые пароли и пароли, привязанные к устройству (не синхронизируемые), на странице управления паролями.

Более подробные инструкции см. в разделе «Регистрация пароля на стороне сервера».

Сообщите, если регистрация не удалась.

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

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

// 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.
    ...
  }
}

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

Отправить уведомление пользователю

Отправка уведомления (например, по электронной почте) о регистрации пароля помогает пользователям выявлять несанкционированный доступ к учетной записи. Если злоумышленник создает пароль без ведома пользователя, он остается доступным для дальнейшего использования, даже после смены пароля. Уведомление предупреждает пользователя и помогает предотвратить это.

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

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

Ресурсы

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