Unified Identity Management logo figure Unified Identity Management logo figure

Аутентификация по протоколу WebAuthn на основе биометрических данных

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

UIDM позволяет выполнять аутентификацию пользователей с использованием современного протокола Web Authentification API (далее — WebAuthN), в том числе на основе биометрических данных — распознавания лица, отпечатка пальца и других сведений об уникальных биологических характеристиках пользователя. В соответствии с протоколом WebAuthN биометрические данные используются только на стороне клиентского устройства (аутентификатора) и по сети не передаются.

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

В основе протокола WebAuthN лежит надёжная асимметричная криптография (криптография с открытым ключом).

Создание ключей и аутентификация по протоколу WebAuthN

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

Для регистрации открытого ключа пользователя в UIDM пользовательским устройством создаётся закрытый (приватный) ключ и открытый (публичный) ключ, которые вместе называются ключевой парой.

Закрытый (приватный) ключ используется пользователем для подписания направляемых им сообщений.

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

Закрытый ключ сохраняется на пользовательском устройстве в защищённом хранилище аутентификатора (программного компонента или устройства).

Открытый ключ вместе со идентификатором (логином) пользователя направляется на сервер и сохраняется на нём⁠[1].

Аутентификация

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

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

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

  • сервер направляет стороне, запрашивающей аутентификацию, challenge (случайное число);

  • запрашивающая аутентификацию сторона (пользователь) подписывает это число закрытым ключом из ключевой пары, созданной для аутентификации на этом ресурсе;

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

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

При аутентификации по протоколу WebAuthN может предоставляться сертификат ключевой пары, выданный третьей доверенной (удостоверяющей) стороной. Открытый ключ пользователя, направляемый на сервер, подписывается удостоверяющей стороной (закрытым ключом). Сервер, используя открытый ключ удостоверяющей стороны, проверяет подпись удостоверяющей стороны.

webauthn
Рисунок 1. Схема работы протокола Web Authentification API (WebAuthN)

Сценарии с использованием протокола WebAuthN

Регистрация устройства для аутентификации на основе биометрических данных

Предварительные требования
  • Выполнена аутентификация пользователя (в браузере сохранён токен доступа).

  • Устройство поддерживает технологию WebAuthN.

Сценарий
  1. Пользователь переходит на страницу управления способами аутентификации.

  2. Браузер отображает элемент пользовательского интерфейса (кнопку), указывающий на возможность привязать устройство.

  3. При нажатии на кнопку выполняется запрос API: Инициализация сценария привязки для получения параметров электронной подписи. Текущий токен доступа передается браузером автоматически.

  4. Сервер генерирует случайное число (nonce) и возвращает его в ответе.

  5. Клиентский код вызывает метод credentials.create().

  6. Пользователь разрешает генерацию ключевой пары и выполняет другие действия, которые ему предлагает операционная система (например, прикладывает палец к сканеру отпечатка пальца или выполняет распознавание лица). Серверу возвращаются объекты clientJson, attestation.

  7. Браузер выполняет запрос API: Привязка нового ключа на регистрацию открытого ключа. Передаются execution, clientData, attestation.

  8. Сервер выполняет проверки clientData, attestation в соответствии со спецификацией WebAuthN.

  9. Сервер создает запись в таблице CertificateCredentials, в которой открытый ключ ассоциируется с логином пользователя.

Аутентификация на ранее зарегистрированном устройстве

Предварительные требования
Сценарий
  1. Пользователь переходит на страницу выбора способа аутентификации.

  2. Браузер отображает элемент пользовательского интерфейса (кнопку), указывающую на возможность аутентификации по протоколу WebAuthN.

  3. При нажатии выполняется запрос API: Инициализация сценария аутентификации на получение параметров подписания. Текущий токен доступа передается браузером автоматически.

  4. Сервер генерирует случайное число (nonce) и возвращает его в ответе.

  5. Клиентский код вызывает метод credentials.get().

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

  7. Браузер выполняет запрос API: Аутентификация с открытым ключом из ключевой пары на аутентификацию с использованием протокола WebAuthN. Передаются execution, credentialId, authenticatorData, clientData, userHandle, signature.

  8. Сервер выполняет проверки переданных данных в соответствии со спецификацией WebAuthN.

  9. Сервер выполняет поиск в таблице CertificateCredentials. Если открытый ключ зарегистрирован, аутентификация считается успешной.

  10. Сервер вызывает сервис auth, находящийся в составе Digital Back, метод /auth/user/:id.

  11. Выполняется запись события аутентификации в БД аудита.

  12. Выпускаются и возвращаются токен доступа, токен обновления доступа.

Спецификация API

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

Инициализация сценария привязки

Запрос
POST {host}/{webauthn-endpoint-path}/webauthn/addInitiate
Content-Type: application/json
Accept: application/json
Cookie: at=...

Часть пути эндпоинта настраивается: значение {webauthn-endpoint-path} устанавливается настройкой окружения экземпляра UIDM.

Cookie авторизации с префиксом подставляется браузером автоматически.

Наименование префикса, добавляемого к cookie авторизации, настраивается: его значение устанавливается настройкой окружения экземпляра UIDM. Значение префикса по умолчанию — at.

Тело запроса отсутствует.

Успешный ответ
HTTP 200 OK
Пример тела ответа
{
    "continuationKey": "b409234f-25b5-4e7f-b632...",
    "approvalInfo": {
        "serverNonce": "1234",
        "rpId": "uidm.ru",
    },
    "form": { ... },
    "status": "approval_required"
}

Наличие в ответе поля status со значением approval_required означает, что можно перейти к шагу API: Привязка нового ключа.

Из ответа на запрос необходимо сохранить значение атрибута continuationKey.

Также из ответа необходимо сохранить значения полей rpId и serverNonce и передать их в качестве значений для параметров rpId и challenge методу create() WebAuthN.

Привязка нового ключа

Запрос
POST {host}/uidm-webapi-1/webauthn/add
Content-Type: application/json
Accept: application/json
Cookie: at=...
Тело (параметры) запроса
{
    "continuationKey": "...",
    "attestation": "...",
    "clientData": "..."
}
Таблица 1. Описание параметров запроса
Переменная Описание Комментарий

continuationKey

Токен поддержания сценария

Передается последний полученный от сервера

attestation

Base64-кодированная строка AuthenticatorAttestationResponse.attestationObject

https://developer.mozilla.org/en-US/docs/Web/API/AuthenticatorAttestationResponse/attestationObject

clientData

Base64-кодированная строка AuthenticatorAttestationResponse.clientDataJSON

https://developer.mozilla.org/en-US/docs/Web/API/AuthenticatorResponse/clientDataJSON

Успешный ответ
HTTP 200 OK
Пример тела ответа
{
   "status": "done"
}

Наличие в ответе поля status со значением done означает, что публичный ключ успешно привязан к идентификатору пользователя.

Аутентификация на основе протокола WebAuthN

Инициализация сценария аутентификации

Запрос
POST {host}/sso/oauth2/access_token
Content-Type: application/x-www-form-urlencoded
Accept: application/json
Тело (параметры) запроса⁠[2]
client_id=oauth_front_m2m&
client_secret=password&
realm=/customer&
grant_type=urn:roox:params:oauth:grant-type:m2m&
service=login-by-Webauthn
Таблица 2. Описание параметров запроса
Переменная Описание Комментарий

client_id

Идентификатор приложения

client_secret

Секрет приложения

Передается, если сейчас работает m2m-протокол. Если /oauth/authorize, то параметр не передается

Успешный ответ
HTTP 200 OK
Пример успешного ответа
{
    "execution": "b409234f-25b5-4e7f-b632...",
    "view": {
        "serverNonce": "1234",
        "rpId": "uidm.ru",
    },
    "form": { … },
    "step": "webauthn-assertion"
}

Наличие в ответе поля step со значением webauthn-assertion означает, что можно перейти к шагу API: Аутентификация с открытым ключом из ключевой пары.

Из ответа на запрос необходимо сохранить значение атрибута execution.

Также из ответа необходимо сохранить значения полей rpId и serverNonce и передать их в качестве значений для параметров rpId и challenge методу create() WebAuthN.

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

Запрос
POST {host}/sso/oauth2/access_token
Content-Type: application/x-www-form-urlencoded
Accept: application/json
Тело (параметры) запроса⁠[3]
client_id=oauth_front_m2m&
client_secret=password&
realm=/customer&
grant_type=urn:roox:params:oauth:grant-type:m2m&
execution=<1234>&
_eventId=next&
credentialId=<ABCD>&
authenticatorData=<ABCD>&
clientData=<ABCD>&
userHandle=<sso_1>&
signature=<ABCD>

Значения параметров execution, credentialId, authenticatorData, clientData, userHandle, signature даны условно.

Таблица 3. Описание параметров запроса
Переменная Описание Комментарий

client_id

Идентификатор приложения

client_secret

Секрет приложения

Передается, если сейчас работает m2m протокол.

Если /oauth/authorize, то параметр не передается

execution

Токен поддержания сценария

Передается последнее значение execution, полученное от сервера в ходе выполнения сценария

credentialId

Идентификатор credential.id

authenticatorData

Base64-кодированная строка AuthenticatorAssertionResponse.authenticatorData

clientData

Base64-кодированная строка AuthenticatorAssertionResponse.clientData

userHandle

UTF-8 cтрока AuthenticatorAssertionResponse.userHandle

Пример преобразования:

var decoder = new TextDecoder("utf-8");

function ab2str(buf) {
   return decoder.decode(new Uint8Array(buf));
}

Кодировка Base64 здесь не используется, поскольку это строка в кодировке UTF-8.

signature

Base64-кодированная строка AuthenticatorAssertionResponse.signature

Успешный ответ
HTTP 200 OK
Пример тела ответа
{
    "access_token": "..."
}

Наличие токена доступа (access_token) в теле ответа означает, что аутентификация выполнена успешно.

Полезные ссылки

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