告别漫长等待:Zoho 升级通行密钥与 Credential Manager,登录快人 “六“ 步

作者 / 高级开发者关系工程师 Niharika Arora、技术撰稿人 Joseph Lewis 及 Zoho 产品经理 Kumareshwaran Sreedharan

Android 开发者一直在寻找可以增强安全性、改善用户体验和简化开发的方法。Zoho 作为一款以安全性和无缝体验为核心的综合性云端软件套件,通过在其 OneAuth Android 应用中采用通行密钥,取得了显著改进。

🔗 OneAuth

https://play.google.com/store/apps/details?id=com.zoho.accounts.oneauth&hl=en_IN

自 2024 年集成通行密钥以来,Zoho 的登录速度相较以往提升了高达 6 倍,通行密钥采用率月环比 (MoM) 增长 31%。

本案例探讨了 Zoho 如何通过采用通行密钥和 Android Credential Manager API 来解决身份验证问题。本文详细介绍了技术实现过程,并重点说明了其显著成果。

🔗 Credential Manager API

https://developer.android.com/training/sign-in/passkeys

克服身份验证挑战

Zoho 使用多种身份验证方法来保护用户账号。这包括其自研的多重身份验证 (MFA) 解决方案——Zoho OneAuth,它既能支持基于密码的验证,还支持使用推送通知、二维码和基于时间的一次性密码 (TOTP) 来实现无密码的身份验证。Zoho 还支持联合登录,允许通过安全断言标记语言 (SAML) 和其他第三方身份验证提供商进行身份验证。

🔗 OneAuth

https://www.zoho.com/accounts/oneauth/

挑战

与许多企业一样,Zoho 也致力于提升身份验证安全性和用户体验,并借此减轻运营负担。促使 Zoho 采用通行密钥的主要挑战包括:

  • 安全漏洞:传统的密码验证方法让用户容易受到网络钓鱼攻击及密码泄露的影响。

  • 用户痛点:"密码疲劳" 会导致用户忘记密码、沮丧失措,不得不依赖繁琐的密码找回流程。

  • 运营效率低下:处理密码重置和多重身份验证 (MFA) 问题产生了大量支持开销。

  • 可扩展性问题:不断增长的用户群体需要更安全、更高效的身份验证解决方案。

为什么要转用通行密钥?

Zoho 在其应用中部署了通行密钥功能以解决身份验证挑战,通过提供无密码方法来显著提高安全性和用户体验。该解决方案采用了防网络钓鱼身份验证、云端同步凭据实现轻松的跨设备访问,以及用于安全登录的生物识别技术 (例如指纹或面部识别)、PIN 码或图案,进而减少了传统密码所带来的漏洞与不便。

通过采用通行密钥和 Credential Manager,Zoho 将登录速度提升了高达 6 倍,降低了与密码相关的支持成本,并获得了极高的用户采用率,通行密钥登录次数在 4 个月内翻了一番,月环比 (MoM) 增长 31%。Zoho 用户现在可以享受更快、更轻松的登录体验和可抵御网络钓鱼攻击的安全保障。

在 Android 上

集成 Credential Manager

Zoho 取得这些成果的秘诀在于,他们使用了 Android 的 Credential Manager API,官方推荐的用于在 Android 上实现身份验证的 Jetpack 库。

Credential Manager 提供了统一的 API,简化了对各种身份验证方法的处理。您可以使用单一接口,而无需为密码、通行密钥和联合登录 (如使用 Google 登录) 调用不同 API。

在 Zoho 中实现通行密钥需要对客户端和服务器端进行调整。以下是通行密钥创建、登录和服务器端实现过程的详细说明。

通行密钥创建

要创建通行密钥,应用首先要在 Zoho 的服务器中检索配置详情。该流程包括一项独特的验证环节,如指纹或面部识别。应用会使用该验证数据 (格式为 requestJson 字符串) 来构建 CreatePublicKeyCredentialRequest。随后,应用会调用 credentialManager.createCredential 方法,该方法会提示用户使用其设备屏幕锁定方式 (生物识别、指纹、PIN 码等) 进行身份验证。

🔗 创建通行密钥

https://developer.android.com/identity/sign-in/credential-manager#registration-flows

用户确认成功后,应用会收到新的通行密钥凭据数据,并将其发送回 Zoho 的服务器进行验证,然后服务器会存储该通行密钥信息,并将其与用户账户关联。应用会捕捉并处理在此过程中出现的操作失败或用户取消的操作。

登录

Zoho Android 应用通过从 Zoho 的后端服务器请求登录选项 (包括唯一 challenge) 来启动通行密钥登录流程。然后,应用会使用该数据构建 GetCredentialRequest,说明它将使用通行密钥进行身份验证。接着,应用会通过该请求调用 Android CredentialManager.getCredential() API。该操作会触发原生 Android 系统界面,提示用户选择其 Zoho 帐户 (如果存在多个通行密钥),并使用其设备配置的屏幕锁定方式 (指纹、面部识别或 PIN 码) 进行身份验证。身份验证成功后,Credential Manager 会将已签名的断言 (登录证明) 发送回 Zoho 应用。应用会将该断言转发到 Zoho 的服务器,服务器会根据用户存储的公钥对签名进行验证,并校验 challenge,从而完成安全登录过程。

🔗 通行密钥登录

https://developer.android.com/identity/sign-in/credential-manager#sign-in

服务器端的实现

Zoho 之所以能顺利过渡到通行密钥体系,得益于其后端系统已符合 FIDO WebAuthn 标准,简化了服务器端的实现流程。但要完全集成通行密钥功能,仍然需要进行特定修改。

最核心的挑战莫过于对凭据存储系统的调整。Zoho 现有的身份验证方法主要使用密码和用于多因素身份验证的 FIDO 安全密钥,相比于基于加密公钥的通行密钥,它们需要不同的存储方法。为了解决这个问题,Zoho 实施了全新的数据库架构,旨在根据 WebAuthn 协议安全地存储通行密钥的公钥和相关数据。该新系统还内置了一个查找机制,以便根据用户和设备信息验证和检索凭据,从而确保能够向后兼容旧版身份验证方法。

另一个服务器端调整是赋予其处理 Android 设备请求的能力。源自 Android 应用的通行密钥请求使用唯一源格式 (android:apk-key-hash:example),该格式与使用基于 URI 的格式 (https://example.com/app) 的标准 Web 源不同。更新服务器逻辑以后,系统才能正确解析该格式,提取应用签名证书的 SHA-256 指纹哈希 (fingerprint hash),并根据预先注册的列表进行验证。该验证步骤可确保身份验证请求都确实来源于 Zoho 的 Android 应用,并防御网络钓鱼攻击。

以下代码段演示了服务器如何检查 Android 特有的源格式并验证证书哈希:

val origin: String = clientData.getString("origin")if (origin.startsWith("android:apk-key-hash:")) {     val originSplit: List<String> = origin.split(":")    if (originSplit.size > 3) {               val androidOriginHashDecoded: ByteArray = Base64.getDecoder().decode(originSplit[3])                if (!androidOriginHashDecoded.contentEquals(oneAuthSha256FingerPrint)) {            throw IAMException(IAMErrorCode.WEBAUTH003)        }    } else {        // Optional: Handle the case where the origin string is malformed    }}

错误处理

Zoho 建立了一套稳健的错误处理机制,以管理面向用户和开发者的错误。当用户手动取消其通行密钥设置时,会出现一个常见错误,即 CreateCredentialCancellationException。Zoho 会追踪该错误出现的频率,以评估潜在的用户体验改进。根据 Android 的用户体验建议,Zoho 采取了相应措施来更好地向其用户普及通行密钥,确保用户了解通行密钥的可用性,并鼓励用户在后续登录时积极尝试启用通行密钥。

🔗 错误处理机制

https://developer.android.com/identity/sign-in/credential-manager-troubleshooting-guide

🔗 用户体验建议

https://developer.android.com/design/ui/mobile/guides/patterns/passkeys

以下代码示例演示了 Zoho 处理最常见的通行密钥创建异常的方法:

private fun handleFailure(e: CreateCredentialException) {    val msg = when (e) {        is CreateCredentialCancellationException -> {            Analytics.addAnalyticsEvent(eventProtocol: "PASSKEY_SETUP_CANCELLED", GROUP_NAME)            Analytics.addNonFatalException(e)            "The operation was canceled by the user."        }        is CreateCredentialInterruptedException -> {            Analytics.addAnalyticsEvent(eventProtocol: "PASSKEY_SETUP_INTERRUPTED", GROUP_NAME)            Analytics.addNonFatalException(e)            "Passkey setup was interrupted. Please try again."        }        is CreateCredentialProviderConfigurationException -> {            Analytics.addAnalyticsEvent(eventProtocol: "PASSKEY_PROVIDER_MISCONFIGURED", GROUP_NAME)            Analytics.addNonFatalException(e)            "Credential provider misconfigured. Contact support."        }        is CreateCredentialUnknownException -> {            Analytics.addAnalyticsEvent(eventProtocol: "PASSKEY_SETUP_UNKNOWN_ERROR", GROUP_NAME)            Analytics.addNonFatalException(e)            "An unknown error occurred during Passkey setup."        }        is CreatePublicKeyCredentialDomException -> {            Analytics.addAnalyticsEvent(eventProtocol: "PASSKEY_WEB_AUTHN_ERROR", GROUP_NAME)            Analytics.addNonFatalException(e)            "Passkey creation failed: ${e.domError}"        }        else -> {            Analytics.addAnalyticsEvent(eventProtocol: "PASSKEY_SETUP_FAILED", GROUP_NAME)            Analytics.addNonFatalException(e)            "An unexpected error occurred. Please try again."        }    }}

在内网环境中测试通行密钥

在封闭的内网环境中测试通行密钥时,Zoho 遇到了第一项挑战。Google 密码管理器的通行密钥验证流程需要公共域名访问权限才能验证信赖方 (RP) 域名。但是,Zoho 的内部测试环境缺乏此类公共互联网访问权限,这导致验证流程无法完成,使得通行密钥的身份认证测试无法顺利进行。为解决这个问题,Zoho 创建了一个可公开访问的测试环境,包括托管一个具有资产链接文件和域名验证功能的临时服务器。

🔗 验证流程

https://developer.android.com/identity/sign-in/credential-manager#add-support-dal

🔗 资产链接文件

https://developer.android.com/identity/sign-in/credential-manager#add-support-dal

以下示例出自 Zoho 公共测试环境中使用的 assetlinks.json 文件,演示了如何将信赖方域名与指定的 Android 应用关联以进行通行密钥验证。

[    {        "relation": [            "delegate_permission/common.handle_all_urls",            "delegate_permission/common.get_login_creds"        ],        "target": {            "namespace": "android_app",            "package_name": "com.zoho.accounts.oneauth",            "sha256_cert_fingerprints": [                "SHA_HEX_VALUE"             ]        }    }]

与现有 FIDO 服务器集成

Android 的通行密钥系统采用现代 FIDO2 WebAuthn 标准,要求各类请求均使用特定的 JSON 格式,这有助于保持原生应用和 Web 平台之间的一致性。为了实现 Android 通行密钥支持,Zoho 进行了一些微小的兼容性和结构调整,以正确生成和处理符合 FIDO2 JSON 结构规范的请求。

该服务器更新涉及几项具体的技术调整:

1. 编码转换:服务器在存储相关数据之前,会将 Base64 URL 编码 (通常在 WebAuthn 中用于凭据 ID 等字段) 转换为标准 Base64 编码。以下代码片段展示了如何将 rawId 编码为标准 Base64 代码:

// Convert rawId bytes to a standard Base64 encoded string for storageval base64RawId: String = Base64.getEncoder().encodeToString(rawId.toByteArray())

2. 传输列表格式:为确保数据处理的一致性,服务器逻辑会将传输机制 (如 USB、NFC 和蓝牙,它们会指定身份验证器的通信方式) 列表转化为 JSON 数组。

3. 客户端数据对齐:Zoho 团队调整了服务器对 clientDataJson 字段的编码和解码方式。这可确保数据结构与 Zoho 现有内部 API 的期望完全一致。以下示例说明了在服务器进行处理客户端数据之前所执行的部分转换逻辑:

private fun convertForServer(type: String): String {    val clientDataBytes = BaseEncoding.base64().decode(type)    val clientDataJson = JSONObject(String(clientDataBytes, StandardCharsets.UTF_8))    val clientJson = JSONObject()    val challengeFromJson = clientDataJson.getString("challenge")    // 'challenge' is a technical identifier/token, not localizable text.    clientJson.put("challenge", BaseEncoding.base64Url()        .encode(challengeFromJson.toByteArray(StandardCharsets.UTF_8)))     clientJson.put("origin", clientDataJson.getString("origin"))    clientJson.put("type", clientDataJson.getString("type"))    clientJson.put("androidPackageName", clientDataJson.getString("androidPackageName"))    return BaseEncoding.base64().encode(clientJson.toString().toByteArray())}

用户指南和身份验证偏好

Zoho 通行密钥策略的核心环节在于鼓励用户采纳,同时提供灵活性以适应不同组织团队的需求。这是通过精细的界面设计和策略管控来实现的。

Zoho 意识到各类组织团队有不同的安全需求。为此采取了以下措施:

  • 管理员强制执行:通过 Zoho Directory 管理面板,管理员可以将通行密钥指定为整个组织的强制性默认身份验证方法。启用此策略后,员工需要在下次登录时设置通行密钥并在后续登录中使用。

  • 用户自主选择:如果组织未启用强制执行,则个人用户将保有对其登录方式的完全控制权。他们可以在登录时,通过身份验证来设置在通行密钥或其他配置选项中选择偏好的身份验证方法。

🔗 Zoho Directory

https://www.zoho.com/directory/

为了提升通行密钥对最终用户的吸引力,并简化其启用流程,Zoho 实现了以下功能:

  • 轻松设置:Zoho 将通行密钥设置直接集成到了 Zoho OneAuth 移动应用中 (支持 Android 和 iOS)。用户可以随时在应用中轻松配置通行密钥,实现无缝过渡。

  • 一致的访问权限:在各个核心用户场景中支持通行密钥,确保用户可以通过以下入口使用通行密钥进行注册和身份验证:

  • Zoho OneAuth 移动应用 (Android 版及 iOS 版);

  • Zoho 网页版帐户页面。

🔗 Android

https://play.google.com/store/apps/details?id=com.zoho.accounts.oneauth&hl=en_IN

🔗 iOS

https://apps.apple.com/in/app/authenticator-app-oneauth/id1142928979

🔗 帐户

https://accounts.zoho.com/home#multiTFA/pfamodes

如此一来,无论是依靠管理员强制执行还是依靠用户自行选择,Zoho 都可确保设置和使用通行密钥的流程,是易于访问的并已集成到用户正在使用的平台中。您可以通过探索我们全面的通行密钥用户体验指南,详细了解如何为通行密钥身份验证打造流畅的用户流程。

🔗 通行密钥用户体验指南

https://developer.android.com/design/ui/mobile/guides/patterns/passkeys

对开发者速度

和集成效率的影响

Credential Manager 作为一个统一的 API,与以往登录流程相比,亦有助于提高开发者的生产力。它降低了分别处理多种身份验证方法和 API 的复杂性,将集成时间由数月缩短到数周,并减少了实现错误。这全面简化了登录流程并提高了整体可靠性。

通过使用 Credential Manager 集成通行密钥功能,Zoho 全面实现了显著、可量化的改进:

  • 显著的速度提升

  • 相比于传统的密码身份验证方式,登录速度提升 2 倍。

  • 相比于使用电子邮件或短信一次性密码 (OTP) 来验证用户名或手机号码的身份验证方式,登录速度提升 4 倍。

  • 相比于使用用户名、密码及短信或身份验证器 OTP 的身份验证方式,登录速度提升 6 倍。

  • 支持成本降低

  • 减少了与密码相关的支持请求,尤其是忘记密码的情况。

  • 降低了与基于短信的 2FA (双重身份验证) 相关的成本,因为现有用户可以直接使用通行密钥登录。

  • 出色的用户采用率及增强的安全性

  • 通行密钥登录次数在短短 4 个月内翻了一番,体现出用户接受度很高。

  • 迁移到通行密钥功能的用户可获得全面保护,有效抵御常见的网络钓鱼和密码泄露的威胁。

  • 随着采用率月环比增长 31%,针对网络钓鱼和 SIM 卡交换等漏洞的安全性得到增强,越来越多的用户每天都能从中受益。

建议和最佳实践

要在 Android 上成功实现通行密钥功能,开发者应考虑以下最佳实践:

  • 利用 Android 的 Credential Manager API:

  • Credential Manager 可简化凭据检索,减少开发者的工作量,并确保提供统一的身份验证体验。

  • 通过单一接口,统一处理密码、通行密钥及联合登录等多种登录流程。

  • 从其他 FIDO 身份验证解决方案迁移时,确保数据编码的一致性:

  • 从其他 FIDO 身份验证解决方案 (如 FIDO 安全通行密钥) 迁移时,请确保所有输入/输出的格式保持一致。

  • 优化错误处理和日志记录:

  • 构建完善的错误处理机制,以实现无缝用户体验。

  • 提供本地化错误提示,并使用详细的日志来调试和解决意外故障。

  • 向用户介绍通行密钥恢复选项:

  • 积极引导用户了解各种恢复选项,以防止出现账户锁定情况。

  • 监控采用指标和用户反馈:

  • 追踪用户参与度、通行密钥采用率和登录成功率,以持续优化用户体验。

  • 对不同的身份验证流程进行 A/B 测试,以提高转化率和留存率。

通过将通行密钥与 Android Credential Manager API 结合使用,可提供强大且统一身份验证解决方案,在增强安全性的同时简化用户体验。通行密钥可显著降低网络钓鱼风险,同时减少凭据盗窃和未经授权的访问。我们鼓励开发者在其应用中尝试这种体验,为用户提供安全的身份验证方式。

🔗 Android Credential Manager API

https://developer.android.com/training/sign-in/passkeys

开始使用通行密钥

和 Credential Manager

使用我们的公开示例代码,在 Android 上亲自体验通行密钥和 Credential Manager。

🔗 公开示例代码

https://github.com/android/identity-samples/tree/credman-compose

如果您有任何疑问或问题,可通过 Android 凭据问题跟踪器与我们分享。欢迎您持续关注 "Android 开发者" 微信公众号,及时了解更多开发技术和产品更新等资讯动态!

🔗 Android 凭据问题跟踪器

https://issuetracker.google.com/issues?q=1301097


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值