Помогите пользователям с одноразовыми паролями, полученными по SMS
Что такое API WebOTP?
Сегодня большинство людей в мире владеют мобильными устройствами, и разработчики часто используют номера телефонов в качестве идентификатора пользователей своих услуг.
Существует множество способов подтверждения номера телефона, но одним из самых распространённых является случайно сгенерированный одноразовый пароль (OTP), отправляемый по SMS. Отправка этого кода обратно на сервер разработчика подтверждает контроль над номером телефона.
Эта идея уже применяется во многих сценариях для достижения:
- Номер телефона как идентификатор пользователя. При регистрации в новой услуге некоторые сайты запрашивают номер телефона вместо адреса электронной почты и используют его в качестве идентификатора учётной записи.
- Двухэтапная аутентификация. При входе на сайт запрашивается одноразовый код, отправленный по SMS, помимо пароля или другого фактора безопасности для дополнительной безопасности.
- Подтверждение платежа. Запрос одноразового кода, отправленного по SMS, при совершении платежа может помочь проверить намерения пользователя.
Текущий процесс создаёт неудобства для пользователей. Поиск одноразового пароля в SMS-сообщении, а затем его копирование и вставка в форму — это обременительно, что снижает конверсию в критически важных для пользователя ситуациях. Упрощение этого процесса — давняя просьба к веб-разработчикам от многих крупнейших мировых разработчиков. У Android есть API, который делает именно это . То же самое делают iOS и Safari .
API WebOTP позволяет вашему приложению получать специально отформатированные сообщения, привязанные к домену вашего приложения. Это позволяет программно получать одноразовые пароли из SMS-сообщений и упрощать проверку номера телефона пользователя.
Посмотрите на это в действии
Предположим, пользователь хочет подтвердить свой номер телефона на сайте. Сайт отправляет пользователю SMS-сообщение, и пользователь вводит одноразовый пароль из сообщения, чтобы подтвердить право собственности на номер телефона.
Благодаря API WebOTP все эти действия выполняются пользователем одним касанием, как показано в видео. При получении SMS-сообщения открывается нижняя панель с предложением подтвердить номер телефона. После нажатия кнопки «Подтвердить» на нижней панели браузер вставляет одноразовый пароль в форму, и форма отправляется без необходимости нажимать кнопку «Продолжить» .
Весь процесс схематически представлен на рисунке ниже.

Попробуйте демо-версию сами. Она не запрашивает ваш номер телефона и не отправляет SMS на ваше устройство, но вы можете отправить SMS с другого устройства, скопировав текст, отображаемый в демо-версии. Это работает, потому что при использовании API WebOTP отправитель не имеет значения.
- Перейдите по адресу https://chrome.dev/web-otp-demo в Chrome 84 или более поздней версии на устройстве Android.
- Отправьте на свой телефон следующее SMS-сообщение с другого телефона.
Your OTP is: 123456.
@chrome.dev #123456
Вы получили SMS и увидели приглашение ввести код в поле ввода? Именно так работает API WebOTP для пользователей.
Использование API WebOTP состоит из трех частей:
- Правильно аннотированный тег
<input>
- JavaScript в вашем веб-приложении
- Форматированный текст сообщения, отправленного по SMS.
Сначала я расскажу о теге <input>
.
Аннотируйте тег <input>
Сам WebOTP работает без каких-либо HTML-аннотаций, но для кроссбраузерной совместимости я настоятельно рекомендую вам добавить autocomplete="one-time-code"
в тег <input>
там, где вы ожидаете, что пользователь введет одноразовый пароль.
Это позволяет Safari 14 или более поздней версии предлагать пользователю автоматически заполнить поле <input>
одноразовым паролем при получении SMS-сообщения в формате, описанном в разделе Форматирование SMS-сообщения, даже если оно не поддерживает WebOTP.
HTML
<form>
<input autocomplete="one-time-code" required/>
<input type="submit">
</form>
Используйте API WebOTP
Поскольку WebOTP прост, достаточно просто скопировать и вставить следующий код. Я в любом случае покажу вам, что происходит.
JavaScript
if ('OTPCredential' in window) {
window.addEventListener('DOMContentLoaded', e => {
const input = document.querySelector('input[autocomplete="one-time-code"]');
if (!input) return;
const ac = new AbortController();
const form = input.closest('form');
if (form) {
form.addEventListener('submit', e => {
ac.abort();
});
}
navigator.credentials.get({
otp: { transport:['sms'] },
signal: ac.signal
}).then(otp => {
input.value = otp.code;
if (form) form.submit();
}).catch(err => {
console.log(err);
});
});
}
Обнаружение особенностей
Обнаружение функций происходит так же, как и во многих других API. Прослушивание события DOMContentLoaded
предполагает ожидание готовности DOM-дерева к выполнению запроса.
JavaScript
if ('OTPCredential' in window) {
window.addEventListener('DOMContentLoaded', e => {
const input = document.querySelector('input[autocomplete="one-time-code"]');
if (!input) return;
…
const form = input.closest('form');
…
});
}
Обработать одноразовый пароль
API WebOTP сам по себе достаточно прост. Используйте метод navigator.credentials.get()
для получения одноразового пароля. WebOTP добавляет к этому методу новый параметр otp
. У него есть только одно свойство: transport
, значение которого должно быть массивом со строкой 'sms'
.
JavaScript
…
navigator.credentials.get({
otp: { transport:['sms'] }
…
}).then(otp => {
…
Это запускает процесс получения разрешений браузера при получении SMS-сообщения. Если разрешение предоставлено, возвращаемое обещание разрешается с помощью объекта OTPCredential
.
Содержание полученного объекта OTPCredential
{
code: "123456" // Obtained OTP
type: "otp" // `type` is always "otp"
}
Затем передайте значение одноразового пароля в поле <input>
. Прямая отправка формы избавит пользователя от необходимости нажимать кнопку.
JavaScript
…
navigator.credentials.get({
otp: { transport:['sms'] }
…
}).then(otp => {
input.value = otp.code;
if (form) form.submit();
}).catch(err => {
console.error(err);
});
…
Отмена сообщения
В случае, если пользователь вручную вводит одноразовый пароль и отправляет форму, вы можете отменить вызов get()
, используя экземпляр AbortController
в объекте options
.
JavaScript
…
const ac = new AbortController();
…
if (form) {
form.addEventListener('submit', e => {
ac.abort();
});
}
…
navigator.credentials.get({
otp: { transport:['sms'] },
signal: ac.signal
}).then(otp => {
…
Форматировать SMS-сообщение
Сам API должен выглядеть достаточно просто, но перед его использованием следует знать несколько моментов. Сообщение должно быть отправлено после вызова navigator.credentials.get()
и получено на устройстве, на котором был вызван get()
. Кроме того, сообщение должно соответствовать следующему форматированию:
- Сообщение начинается с удобочитаемого текста, который содержит строку из четырех-десяти букв и цифр, включающую по крайней мере одну цифру, а последняя строка содержит URL-адрес и одноразовый пароль.
- Доменная часть URL-адреса веб-сайта, вызвавшего API, должна предваряться символом
@
. - URL-адрес должен содержать знак решетки ('
#
'), за которым следует одноразовый пароль.
Например:
Your OTP is: 123456.
@www.example.com #123456
Вот плохие примеры:
Пример неверно сформированного текста SMS | Почему это не сработает |
---|---|
Here is your code for @example.com #123456 | Ожидается, что @ будет первым символом последней строки. |
Your code for @example.com is #123456 | Ожидается, что @ будет первым символом последней строки. |
Your verification code is 123456 @example.com\t#123456 | Между @host и #code ожидается один пробел. |
Your verification code is 123456 @example.com #123456 | Между @host и #code ожидается один пробел. |
Your verification code is 123456 @ftp://example.com #123456 | Схема URL не может быть включена. |
Your verification code is 123456 @https://example.com #123456 | Схема URL не может быть включена. |
Your verification code is 123456 @example.com:8080 #123456 | Порт не может быть включен. |
Your verification code is 123456 @example.com/foobar #123456 | Путь не может быть включен. |
Your verification code is 123456 @example .com #123456 | В домене нет пробелов. |
Your verification code is 123456 @domain-forbiden-chars-#%/:<>?@[] #123456 | В домене нет запрещенных символов . |
@example.com #123456 Mambo Jumbo | @host и #code должны быть последней строкой. |
@example.com #123456 App hash #oudf08lkjsdf834 | @host и #code должны быть последней строкой. |
Your verification code is 123456 @example.com 123456 | Отсутствующий # . |
Your verification code is 123456 example.com #123456 | Отсутствующий @ . |
Hi mom, did you receive my last text | Отсутствуют @ и # . |
Демо-версии
Попробуйте различные сообщения с помощью демо-версии: https://chrome.dev/web-otp-demo
Исходный код можно найти здесь: https://github.com/GoogleChromeLabs/web-identity-demos/tree/main/web-otp-demo .
Использовать WebOTP из кросс-доменного iframe
Ввод одноразового пароля из SMS в кросс-доменный iframe обычно используется для подтверждения платежа, особенно с 3D Secure. API WebOTP, имеющий общий формат для поддержки кросс-доменных iframe, предоставляет одноразовые пароли, привязанные к вложенным источникам. Например:
- Пользователь посещает
shop.example
, чтобы купить пару обуви с помощью кредитной карты. - После ввода номера кредитной карты интегрированный платежный провайдер отображает форму из
bank.example
в iframe, предлагая пользователю подтвердить свой номер телефона для быстрой оплаты. -
bank.example
отправляет пользователю SMS-сообщение, содержащее одноразовый пароль, который он может ввести для подтверждения своей личности.
Чтобы использовать API WebOTP из кросс-доменного iframe, вам необходимо сделать две вещи:
- Укажите в тексте SMS-сообщения как начало верхнего фрейма, так и начало iframe.
- Настройте политику разрешений, чтобы разрешить кросс-источниковому iframe получать одноразовые пароли напрямую от пользователя.
Демо-версию можно опробовать по адресу https://web-otp-iframe-demo.stackblitz.io .
Добавить примечания bound-origins к текстовому сообщению SMS
При вызове API WebOTP из iframe текстовое SMS-сообщение должно включать источник верхнего фрейма, которому предшествует @
, за которым следует одноразовый пароль, которому предшествует #
и источник iframe, которому предшествует @
в последней строке.
Your verification code is 123456
@shop.example #123456 @bank.exmple
Настроить политику разрешений
Чтобы использовать WebOTP в кросс-доменном iframe, интегратор должен предоставить доступ к этому API через политику разрешений otp-credentials, чтобы избежать непреднамеренного поведения. В общем случае, существует два способа достижения этой цели:
через HTTP-заголовок:
Permissions-Policy: otp-credentials=(self "https://bank.example")
через атрибут allow
iframe:
<iframe src="https://bank.example/…" allow="otp-credentials"></iframe>
Дополнительные примеры настройки политики разрешений см.
Используйте WebOTP на компьютере
В Chrome WebOTP поддерживает прослушивание SMS-сообщений, полученных на других устройствах, чтобы помочь пользователям пройти проверку номера телефона на настольном компьютере.
Для этой возможности пользователю необходимо войти в одну и ту же учетную запись Google как на настольном Chrome, так и на Android Chrome.
Все, что нужно сделать разработчикам, — это реализовать API WebOTP на своем десктопном сайте, так же, как они это делают на своем мобильном сайте, но никаких особых ухищрений не требуется.
Более подробную информацию можно найти в статье Проверка номера телефона на компьютере с помощью API WebOTP .
Часто задаваемые вопросы
Диалоговое окно не появляется, хотя я отправляю правильно отформатированное сообщение. Что происходит?
При тестировании API следует учитывать несколько моментов:
- Если номер телефона отправителя включен в список контактов получателя, этот API не будет активирован из-за особенностей конструкции базового API согласия пользователя SMS .
- Если вы используете рабочий профиль на своем Android-устройстве и WebOTP не работает, попробуйте установить и использовать Chrome в своем личном профиле (т. е. в том же профиле, в котором вы получаете SMS-сообщения).
Проверьте формат еще раз, чтобы убедиться, что ваше SMS-сообщение отформатировано правильно.
Совместим ли этот API с различными браузерами?
Chromium и WebKit согласовали формат текстовых SMS-сообщений , а Apple объявила о его поддержке в Safari, начиная с iOS 14 и macOS Big Sur. Хотя Safari не поддерживает JavaScript API WebOTP, благодаря аннотации элемента input
autocomplete=["one-time-code"]
клавиатура по умолчанию автоматически предлагает ввести одноразовый пароль, если SMS-сообщение соответствует формату.
Безопасно ли использовать SMS в качестве способа аутентификации?
Хотя SMS-одноразовые пароли (OTP) полезны для подтверждения номера телефона при его первом предоставлении, проверку номера телефона через SMS следует использовать с осторожностью при повторной аутентификации, поскольку операторы связи могут перехватывать номера и использовать их повторно. WebOTP — удобный механизм повторной аутентификации и восстановления, но сервисам следует сочетать его с дополнительными факторами, такими как проверка знаний, или использовать API веб-аутентификации для надежной аутентификации.
Куда можно сообщить об ошибках в реализации Chrome?
Вы нашли ошибку в реализации Chrome?
- Сообщите об ошибке на сайте crbug.com . Опишите проблему максимально подробно, предоставьте простые инструкции по её воспроизведению и выберите в качестве компонентов
Blink>WebOTP
.
Как я могу помочь этой функции?
Планируете ли вы использовать API WebOTP? Ваша публичная поддержка помогает нам расставлять приоритеты в отношении функций и показывает другим разработчикам браузеров, насколько важна их поддержка. Отправьте твит @ChromiumDev с хэштегом #WebOTP
и расскажите нам, где и как вы его используете.
Ресурсы
- Лучшие практики создания одноразовых паролей SMS
- Подтвердите номер телефона на компьютере с помощью API WebOTP
- Заполняйте формы одноразовых паролей в кросс-доменных iframe с помощью API WebOTP
- Беспарольная аутентификация Yahoo! JAPAN сократила количество запросов на 25%, ускорив время входа в систему в 2,6 раза.