案例研究

Zoho 通过通行密钥和 Credential Manager 集成实现了 6 倍的登录速度提升

阅读用时:10 分钟

作为 Android 开发者,您一直在寻找提升安全性、改善用户体验和简化开发流程的方法。Zoho 是一套全面的基于云的软件套件,专注于安全性和顺畅的体验,通过在其 OneAuth Android 应用中采用通行密钥,实现了显著的改进。

自 2024 年集成通行密钥以来,Zoho 的登录速度比以前的方法快了 6 倍,通行密钥采用率环比增长了 31%

本案例研究探讨了 Zoho 如何采用通行密钥和 Android 的 Credential Manager API 来解决身份验证难题。其中详细介绍了技术实现流程,并重点介绍了取得的显著成效。

克服身份验证难题

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

挑战

与许多组织一样,Zoho 也希望在减轻运营负担的同时,提高身份验证安全性和用户体验。促使 Zoho 采用通行密钥的主要挑战包括:

  • 安全漏洞:基于传统密码的方法让用户容易受到钓鱼式攻击和密码泄露的威胁。
  • 用户摩擦:密码疲劳导致用户忘记密码,感到沮丧,并更加依赖繁琐的恢复流程。
  • 运营效率低下:处理密码重置和 MFA 问题会产生大量支持开销。
  • 可扩缩性问题:不断增长的用户群需要更安全高效的身份验证解决方案。

为什么改用通行密钥?

Zoho 在其应用中实现了通行密钥,旨在通过提供无需密码的方法来解决身份验证难题,从而显著提升安全性和用户体验。此解决方案利用了防钓鱼身份验证、云同步凭据(可轻松实现跨设备访问)以及生物识别(例如指纹或人脸识别)、PIN 码或解锁图案来确保登录安全,从而减少与传统密码相关的漏洞和不便。

通过采用 Credential Manager 通行密钥,Zoho 将登录时间缩短了多达 6 倍,大幅降低了与密码相关的支持成本,并实现了强劲的用户采用率,在 4 个月内将通行密钥登录次数增加了一倍,实现了 31% 的环比增长。Zoho 用户现在可以更快速、更轻松地登录,并享受防钓鱼式攻击的安全性

ANDDM_Zoho_Quote_fabrice.png

在 Android 上使用 Credential Manager 进行实现

那么,Zoho 是如何实现这些成果的呢?他们使用了 Android 的 Credential Manager API,这是在 Android 上实现身份验证的推荐 Jetpack 库。

Credential Manager 提供了一个统一的 API,可简化各种身份验证方法的处理。您只需使用一个接口,即可管理密码、通行密钥和联合登录(例如“使用 Google 账号登录”)。

在 Zoho 中实现通行密钥需要进行客户端和服务器端调整。下面详细介绍了通行密钥创建、登录和服务器端实现流程。

创建通行密钥

passkey.png

如需创建通行密钥,应用首先会从 Zoho 的服务器检索配置详细信息。此流程包括独特的验证方式,例如指纹或人脸识别。此身份验证数据(格式为 requestJson 字符串)由应用用于构建 CreatePublicKeyCredentialRequest。然后,应用会调用 credentialManager.createCredential 方法,该方法会提示用户使用设备屏幕锁定(生物识别信息、指纹、PIN 码等)进行身份验证。

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

登录

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

服务器端实现

Zoho 的通行密钥支持过渡得益于其后端系统已符合 FIDO WebAuthn 标准,这简化了服务器端实现流程。不过,仍需进行特定修改才能完全集成通行密钥功能。

最重大的挑战在于调整凭证存储空间。Zoho 现有的身份验证方法主要使用密码和 FIDO 安全密钥进行多重身份验证,与基于加密公钥的通行密钥相比,需要不同的存储方法。为解决此问题,Zoho 实施了一种新的数据库架构,专门用于根据 WebAuthn 协议安全地存储通行密钥公钥和相关数据。新系统与一种查找机制一起构建,可根据用户和设备信息验证和检索凭据,确保与旧的身份验证方法向后兼容。

另一项服务器端调整涉及实现处理来自 Android 设备的请求的功能。源自 Android 应用的通行密钥请求使用独特的来源格式 (android:apk-key-hash:example),该格式不同于使用基于 URI 的格式 (https://example.com/app) 的标准 Web 来源。需要更新服务器逻辑,以正确解析此格式、提取应用签名证书的 SHA-256 指纹哈希,并根据预注册列表对其进行验证。此验证步骤可确保身份验证请求确实源自 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 的 UX 建议,Zoho 采取了相关措施,以便更好地向用户介绍通行密钥,确保用户了解通行密钥的可用性,并在后续登录尝试期间推广通行密钥。

此代码示例演示了 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 创建了一个可公开访问的测试环境,其中包括托管一个临时服务器,其中包含资源链接文件和网域验证。

此示例来自 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 网址 编码(通常在 WebAuthn 中用于凭据 ID 等字段)转换为标准 Base64 编码。以下代码段展示了如何将 rawId 编码为标准 Base64:

// Convert rawId bytes to a standard Base64 encoded string for storage
val 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 实施了以下措施:

  • 管理员强制执行:通过 Zoho Directory 管理员面板,管理员可以将通行密钥指定为整个组织的强制性默认身份验证方法。如果此政策处于启用状态,员工必须在下次登录时设置通行密钥,并从那时起使用通行密钥。
  • 用户选择:如果组织未强制执行特定政策,则用户可以自行选择。他们可以在登录时选择自己偏好的身份验证方法,通过身份验证设置从通行密钥或其他已配置的选项中进行选择。

为了让最终用户能够轻松采用通行密钥,Zoho 实施了以下措施:

  • 设置简单:Zoho 将通行密钥设置直接集成到 Zoho OneAuth 移动应用(适用于 AndroidiOS)中。用户可以随时在应用内轻松配置通行密钥,从而顺利完成过渡。
  • 一致的访问体验:我们在关键的用户互动点实现了通行密钥支持,确保用户可以通过以下方式使用通行密钥进行注册和身份验证:
  • Zoho OneAuth 移动应用(Android 和 iOS);
  • Zoho 网页版账号页面。

此方法可确保设置和使用通行密钥的过程易于访问,并集成到用户已使用的平台中,无论这是管理员强制执行的还是用户自行选择的。您可以参阅我们全面的通行密钥用户体验指南,详细了解如何为通行密钥身份验证创建顺畅的用户流程。

对开发速度和集成效率的影响

与旧版登录流程相比,Credential Manager 作为统一的 API,还有助于提高开发者工作效率。它降低了分别处理多种身份验证方法和 API 的复杂性,从而缩短了集成时间(从数月缩短至数周),并减少了实现错误。这共同简化了登录流程,并提高了整体可靠性。

通过将通行密钥与 Credential Manager 搭配使用,Zoho 在各个方面都取得了显著且可衡量的改进:

  • 大幅提升速度
    • 与传统的密码身份验证相比,登录速度快 2 倍
    • 与使用电子邮件地址或手机号码通过电子邮件或短信动态密码进行身份验证相比,登录速度快 4 倍
    • 与用户名、密码以及短信或身份验证器动态密码身份验证相比,登录速度快 6 倍
  • 降低支持费用
    • 减少了与密码相关的支持请求,尤其是忘记密码的情况。
    • 与基于短信的两步验证相比,费用更低,因为现有用户可以直接使用通行密钥完成初始配置。
  • 用户采用率高且安全性增强
    • 仅在 4 个月内,使用通行密钥登录的次数就翻了一番,这表明用户对通行密钥的接受度很高。
    • 改用通行密钥的用户可以全面防范常见的钓鱼式攻击和密码泄露威胁。
    • 随着采用率环比增长 31%,每天都有更多用户受益于增强型安全功能,防范钓鱼式攻击和 SIM 卡交换等漏洞。

建议和最佳实践

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

  • 利用 Android 的 Credential Manager API
    • Credential Manager 可简化凭据检索,减少开发者工作量,并确保统一的身份验证体验。
    • 在一个界面中处理密码、通行密钥和联合登录流程。
  • 在从其他 FIDO 身份验证解决方案迁移时,确保数据编码一致性
    • 在从其他 FIDO 身份验证解决方案(例如 FIDO 安全密钥)迁移时,请确保以一致的格式处理所有输入/输出。
  • 优化错误处理和日志记录
    • 实现强大的错误处理功能,打造顺畅的用户体验。
    • 提供本地化错误消息,并使用详细的日志来调试和解决意外故障。
  • 向用户介绍通行密钥账号恢复选项
    • 主动引导用户了解恢复选项,避免出现账号锁定情况。
  • 监控采用情况指标和用户反馈
    • 跟踪用户互动情况、通行密钥采用率和登录成功率,以便不断优化用户体验。
    • 对不同的身份验证流程进行 A/B 测试,以提高转化率和用户留存率。

通行密钥与 Android Credential Manager API 相结合,可提供强大的统一身份验证解决方案,在提升安全性的同时简化用户体验。通行密钥可显著降低钓鱼式攻击、凭据盗窃和未经授权的访问风险。我们鼓励开发者在自己的应用中试用该功能,并为用户提供最安全的身份验证方式。

通行密钥和 Credential Manager 使用入门

使用我们的公开示例代码,在 Android 设备上实际操作通行密钥和 Credential Manager。

如果您有任何问题或疑虑,可以通过 Android 凭据问题跟踪器与我们分享。

作者:

继续阅读