Истории успеха

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

Время на чтение: 8 минут

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

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

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

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

Решение о переходе на ключи доступа

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

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

unnamed.png
Как ключи доступа сохраняются и используются для аутентификации с помощью криптографии с открытым и закрытым ключами
AANDDM_KARROT_Quote_02.png

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

Клиентская интеграция

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

Хотя удачный путь работал с самого начала, навигация по разнообразной пользовательской базе среди OEM-производителей, нескольких версий Android и различных конфигураций устройств (например, только PIN-код по сравнению с биометрическими данными или Android 13 по сравнению с 14+) выявила беспрецедентные крайние случаи. Среди них были пользователи без блокировки экрана, неожиданные типы исключений, устаревшие сервисы Google Play и несогласованное поведение поставщика учетных данных.

Чтобы преодолеть эти препятствия, команды WhatsApp и Google тесно сотрудничали и решили несколько проблем:

  • Оптимизация процесса поиска учетных данных. Первоначальный процесс поиска имел низкую задержку, особенно для пользователей, которые ещё не создали ключ доступа. Поскольку большинство пользователей WhatsApp на ранних этапах попадают в эту категорию, это привело к заметной задержке почти при каждом входе в систему. Проанализировав путь вызова и выявив узкие места, разработчики WhatsApp значительно ускорили процесс и повысили производительность, что в конечном итоге принесло пользу всей экосистеме Android.
  • Обработка временных состояний. WhatsApp создал комплексный уровень обработки ошибок, чтобы справляться с проблемами, связанными с устройствами, такими как доступность менеджера паролей, ненастроенная блокировка экрана, периодические проблемы с подключением, несовместимое оборудование, устаревшие сервисы Google Play, классифицируя исключения на восстанавливаемые и терминальные состояния. Это позволило обеспечить постепенное сокращение: если процесс входа с помощью ключа доступа не удавалось завершить, система безопасно возвращалась к традиционной аутентификации, не оставляя пользователя в нерабочем состоянии.
  • Устранение ошибок, связанных с ОС. Телеметрия показала, что на некоторых устройствах с Android 13 возникает ошибка GetPublicKeyCredentialDomException (не удалось расшифровать учетные данные), а на устройствах с Android 14 при создании ключа доступа – CreatePublicKeyCredentialDomException (не удалось получить аккаунт для синхронизации). Команды Google и WhatsApp выяснили основные причины этих ошибок и внесли улучшения на уровне платформы, чтобы упростить создание ключей доступа. В руководстве по ошибкам перечислены распространенные коды ошибок и описания, связанные с Менеджером учетных данных, а также приведена информация об их причинах. 
Примечание. Дополнительную информацию вы найдете в блоге о рекомендациях по работе с ключами доступа. В нем рассказывается, как сделать переход на ключи доступа удобнее для пользователей.

Улучшение пользовательского опыта

Поскольку в начале 2023 года ключи доступа были совершенно новой концепцией, не существовало устоявшихся шаблонов для предложения их создания. Проведя масштабное A/B-тестирование, разработчики WhatsApp создали контекстную систему, которая нацелена на пользователей, которым функция будет наиболее полезна. Эта стратегия постоянно развивалась: по мере того как процессы ОС Android превращались в оптимизированный одноэкранный интерфейс, WhatsApp упрощал свои собственные подсказки, чтобы избежать избыточного или запутанного пользовательского интерфейса.

Case-Study-1.png
Упрощенный процесс создания ключа доступа в WhatsApp на одном экране

Серверная архитектура и кроссплатформенные препятствия

На сервере WhatsApp реализованы стандартные процедуры WebAuthn/FIDO2. Бэкенд написан на Erlang и вызывает библиотеку Rust webauthn-rs через нативный интерфейс. Эта библиотека Rust обрабатывает проверку подписи и синтаксический анализ учетных данных, позволяя внутреннему коду оставаться сосредоточенным на оркестрации, хранении и правилах продукта, таких как право на участие, ограничение частоты запросов и жизненный цикл учетных данных.

Архитектура сервера управляет этими основными церемониями через четыре основные точки входа, объединенные в последовательности Begin и Finish для регистрации и аутентификации:

1. Регистрация ключа доступа

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

unnamed (1).png
Архитектура взаимодействия сервера и клиента во время регистрации ключа доступа

Erlang: начало регистрации

begin_registration(UserId) ->
    Existing = list_credentials(UserId),
    %% reuse the existing user handle, or mint a new one
    {UserHandle, IsNew} = user_handle(Existing),
    %% returns the client creation options and the server-side challenge state
    #{client_safe := CreationOptions, server_only := ChallengeState} =
        webauthn:start_registration(UserId, UserHandle, rp_config()),
    %% excludeCredentials: the user's existing credential IDs, so the device won't re-enroll one
    Options = with_exclude_credentials(CreationOptions, credential_ids(Existing)),
    store_challenge(UserId, ChallengeState),          %% short TTL
    IsNew andalso reserve_user_handle(UserId, UserHandle),
    Options.
  • Идентификация пользователя. Сервер сначала проверяет наличие существующих учетных данных, чтобы повторно использовать существующий дескриптор пользователя или создать новый.
  • Генерирует параметры и запрос. Вызывает библиотеку WebAuthn, чтобы сгенерировать параметры создания для клиента и безопасное состояние запроса для сервера.
  • Предотвращение дублирования. Исключаются идентификаторы существующих учетных данных пользователя, чтобы устройство случайно не зарегистрировало ключ доступа, который уже зарегистрирован.
  • Сохранение запроса. Сервер временно сохраняет запрос с коротким временем жизни (TTL) и отправляет параметры обратно на клиентское устройство.

Erlang: завершение регистрации

finish_registration(UserId, Attestation) ->
    ChallengeState = get_challenge(UserId),          %% must exist and be unexpired
    #{credential_id := CredId, public_key := PubKey} =
        webauthn:finish_registration(Attestation, ChallengeState, rp_config()),
    ok = index_credential(CredId, UserId),            %% map credential_id -> account
    case multi_passkey_enabled(UserId) of
        true  -> add_credential(UserId, CredId, PubKey);      %% append (oldest evicted past the cap)
        false -> replace_credential(UserId, CredId, PubKey)   %% single-passkey mode
    end,
    notify_client(UserId, {passkey_created, CredId}),
    ok.
  • Получение запроса. Сервер получает сохраненный запрос, проверяя, что он все ещё существует и срок его действия не истек.
  • Проверка подтверждения. Ответ клиента (подтверждение) и запрос передаются в библиотеку WebAuthn, чтобы проверить запрос и извлечь новый идентификатор учетных данных и открытый ключ.
  • Индексирование учетных данных. Идентификатор новых учетных данных сопоставляется напрямую с аккаунтом пользователя, чтобы в дальнейшем их можно было быстро найти.
  • Сохранение и управление ограничениями. В зависимости от того, включена ли функция нескольких ключей доступа, сервер либо добавит новые учетные данные в список пользователя (удалив самые старые, если достигнуто ограничение), либо заменит существующие в режиме одного ключа доступа.

2. Проверка учетных данных

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

Erlang: начать аутентификацию

begin_authentication(UserId) ->
    Credentials = list_valid_credentials(UserId),
    #{client_safe := RequestOptions, server_only := ChallengeState} =
        webauthn:start_authentication(Credentials, rp_config()),
    store_challenge(UserId, ChallengeState),          %% short TTL
    RequestOptions.
  • Получение действительных учетных данных. Сервер ищет все действительные учетные данные, связанные с пользователем.
  • Генерирует запрос. Использует эти учетные данные для создания параметров запроса для клиента и генерирует новый запрос на стороне сервера.
  • Сохранение и возврат. Как и при регистрации, запрос временно сохраняется, а параметры запроса передаются клиентскому приложению.

Erlang: завершение аутентификации

finish_authentication(UserId, Assertion) ->
    ChallengeState = get_challenge(UserId),
    Credentials = list_valid_credentials(UserId),
    case webauthn:finish_authentication(Credentials, Assertion, ChallengeState) of
        #{user_verified := true, credential_id := CredId, needs_update := NeedsUpdate} = Result ->
            %% webauthn tells us when the stored credential should be refreshed
            NeedsUpdate andalso refresh_credential(UserId, CredId, Result),
            mark_credential_used(UserId, CredId),
            {ok, CredId};
        _ ->
            {error, not_allowed}
    end.
  • Проверка утверждения. Сервер извлекает сохраненный запрос и действительные учетные данные, а затем просит библиотеку WebAuthn проверить утверждение клиента.
  • Обновление при необходимости. Если пользователь успешно подтвержден, сервер проверяет флаг needs_update. Библиотека WebAuthn использует этот флаг, чтобы сообщить, нужно ли обновить статус сохраненных учетных данных на сервере.
  • Завершение. Сервер помечает учетные данные как использованные и успешно завершает процесс входа.
Case-Study-2.png
Пошаговая инструкция по входу в приложение WhatsApp с помощью ключа доступа.

Подробную информацию о регистрации сервера можно найти в руководстве по интеграции. 

Дополнительные рекомендации по архитектуре 

Реализация ключей доступа на сервере в больших масштабах создала уникальные проблемы, особенно в отношении архитектуры аккаунта и синхронизации устройств. Ашиш Чоудхари (Ashish Choudhary) из команды разработчиков WhatsApp рассказал о главных трудностях, с которыми они столкнулись:

  1. Переход на несколько ключей доступа для одного аккаунта. Старая серверная логика WhatsApp была тесно связана с предположением, что у каждого пользователя есть только одни учетные данные. Чтобы обеспечить поддержку современных реалий, оптимизированных для любых устройств, они разработали систему ограниченных списков, которая разумно удаляет самые старые учетные данные по достижении лимита. Чтобы обеспечить абсолютную стабильность, это серьезное структурное изменение внедрялось постепенно в ходе тщательных экспериментов.
  2. Баланс жизненного цикла учетных данных. Управление сроком действия учетных данных требовало деликатного подхода. Если делать это слишком часто, пользователям придется постоянно регистрироваться заново, а если слишком редко – будут накапливаться устаревшие учетные данные. Чтобы решить эту проблему, разработчики WhatsApp внедрили сбалансированные состояния жизненного цикла, которые обеспечивают высокий уровень безопасности и не вызывают неудобств у пользователей. Кроме того, была добавлена автоматическая фоновая очистка неактивных ключей доступа.

Новый подход к синхронизации между устройствами

Надежная архитектура с несколькими ключами доступа также позволила WhatsApp полностью переосмыслить удобство использования на разных платформах. Стандартный процесс WebAuthn для нескольких устройств требует сканирования QR-кода на одном устройстве и аутентификации через Bluetooth на другом. Однако в WhatsApp обнаружили, что зависимость от Bluetooth ненадежна, и пользователи часто путали новые QR-коды с существующим процессом связывания WhatsApp Web.

Вместо того чтобы заставлять пользователей переносить ключи доступа с одного устройства на другое, WhatsApp позволяет хранить их в разных экосистемах, например в Google Менеджере паролей на Android и в Связке ключей iCloud на iOS. При переходе на новую платформу пользователям достаточно сгенерировать новый ключ доступа во время следующего входа. Этот подход не требует от пользователя никаких действий и отлично работает на базе новой серверной инфраструктуры с поддержкой нескольких ключей доступа.

Планы на будущее

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

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

Рекомендации для разработчиков, создающих приложения в больших масштабах

Разработчикам, которые планируют внедрить ключи доступа в крупном масштабе, команда WhatsApp рекомендует:

  • Заранее разработайте классификацию ошибок. Разделите все возможные исключения Менеджера учетных данных на устранимые и неустранимые и определите четкие и понятные резервные пути для каждого сценария.
  • Проверяйте соответствие требованиям. Настройте проверку возможностей устройства, например наличия блокировки экрана, биометрического оборудования и версий сервисов Google Play, и разработайте процессы, позволяющие заранее исключать пользователей, не соответствующих требованиям, а не в середине процесса.
  • Подготовьте приложение к резервному копированию. Используйте ключи доступа в качестве основного способа аутентификации на поддерживаемых устройствах, но всегда сохраняйте традиционные методы в качестве надежного универсального резервного варианта.
  • Учитывайте фрагментацию версий ОС. Поведение ключей доступа может различаться в зависимости от операционной системы. Тщательно протестируйте приложение на Android 13, 14 и 15+, а также учтите особенности интерфейса выбора учетных данных у разных производителей.
  • Предлагайте ключи доступа в подходящем контексте и рассказывайте о них. Предлагайте создать ключ доступа, когда пользователь выполняет действия, связанные с безопасностью. Четко подчеркните ценностное предложение (скорость и безопасность), используя доступный язык, чтобы стимулировать внедрение пользователями.
  • Проактивный мониторинг. Экосистема развивается с каждым обновлением ОС. Постоянно отслеживайте задержки и ошибки, чтобы быть в курсе изменений в работе устройств.
AANDDM_Passkeys_Quote_01.png

Начало работы с ключами доступа и Менеджером учетных данных

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

Если у вас возникли вопросы или проблемы, сообщите нам о них через систему отслеживания ошибок Android Credentials.

Автор:
Продолжить чтение