【Android 网络安全】时间偏差如何引爆 SHA-1 证书缺陷?SSL 握手失败的深度分析

96 阅读5分钟

这是一篇针对 Android 开发者和后端运维团队的技术分析博客。我们将基于一个典型的、因 手动修改设备时间 导致的 SSL 握手失败 案例,深入剖析其背后的安全机制和证书链弱点。


一、现象描述与异常日志

当用户手动将 Android 设备时间修改到未来(例如 2025 年)时,应用内使用 Retrofit/OkHttp 发送的 HTTPS 请求会立即失败。奇怪的是,部分接口访问正常,部分接口访问异常

异常请求的日志显示了一个 SSLHandshakeException,核心信息如下:

Code snippet

javax.net.ssl.SSLHandshakeException: Unacceptable certificate: CN=DigiCert Global Root CA...
Caused by: java.security.cert.CertificateException: Signature uses an insecure hash function: 1.2.840.113549.1.1.5

关键线索:

  1. 错误信息指向证书链中的 DigiCert Global Root CA
  2. 根本原因明确指出:证书签名使用了 不安全的哈希函数1.2.840.113549.1.1.5,即 SHA-1 算法)。
  3. 核心测试: 当把设备时间调回 默认系统时间 后,所有接口恢复正常。

二、Bug 根本原因分析:双重安全检查失败

这个问题的本质是 设备时间偏差服务器证书弱点 共同作用的结果,缺一不可。

1. 时间偏差:引爆器(The Trigger)

SSL/TLS 握手 的第一步是验证服务器证书的有效期

  • 证书都有一个明确的 “生效日期”“截止日期”

  • 当你将设备时间修改到 错误的未来错误的过去 时,系统在检查证书有效期时发现:

    • 尚未生效 (Certificate Not Yet Valid)
    • 已过期 (Certificate Expired)
  • 结果: 证书有效期检查失败,握手必须终止。

2. SHA-1 签名:底层弱点(The Flaw)

根据日志,异常接口的服务器提供的证书链中,存在一个或多个证书使用了 SHA-1 签名算法。

  • 官方政策:Android 10 (API 29) 起,TLS 连接中签发给服务器的证书 使用 SHA-1 是 不被信任 的。浏览器和操作系统早已将 SHA-1 视为不安全并逐步淘汰(自 2017 年起)。

    • 参考官方文档: Google 明确指出,在 Android 10 中, “Certificates signed with SHA-1 aren't trusted in TLS.” [1]
  • 系统行为: 尽管证书链存在 SHA-1 弱点,但在 时间正确 的情况下,某些版本的 Android 可能会出于兼容性目的勉强接受

  • 双重失败机制: 当时间检查失败(引爆器)后,Android 的安全模块(TrustManagerImpl 内的 ChainStrengthAnalyzer)会切换到最严格的校验模式,此时它不仅发现时间错误,还发现了证书链中的 SHA-1 弱点(炸弹),并最终以“不安全的哈希函数”作为最明确的错误原因向上抛出异常。

3. 为什么有的接口正常?

接口访问差异的唯一解释是:证书链不同

  • 正常接口: 它们连接的服务器使用了 符合现代安全标准(SHA-256 或更高) 签名的证书链,不包含任何 SHA-1 弱点。因此,即使时间错误,系统的安全检查也能在遇到时间错误时进行优雅降级或兼容处理,不触发致命的 SHA-1 拒绝。
  • 异常接口: 它们连接的服务器使用了包含 SHA-1 弱点 的证书链,一旦时间偏差触发了严格检查,立即暴露并拒绝连接。

三、Charles 代理绕过机制分析

用户发现通过 Charles 代理 访问时,即使时间错误,异常接口也能恢复正常。这进一步证实了问题根源在证书链。

Charles 等抓包工具充当 中间人 (MITM) 代理,其工作流程如下:

  1. 替换证书链: Charles 在设备和服务器之间截断 HTTPS 流量。
  2. 伪造证书: 它会动态生成一张伪造证书给客户端 App。这张证书由安全的 SHA-256 算法签名,并且由已安装在设备中的 Charles Root CA 签发。
  3. 绕过检查: App 收到这张 “干净” 的 Charles 证书,发现它在有效期内(由 Charles 动态设置)且使用了安全的 SHA-256 签名。因此,它成功通过了 Android 的严格安全检查,完成了握手。

结论: Charles 的伪造证书“干净”无弱点,成功绕过了服务器原始证书链的 SHA-1 缺陷


四、解决方案与官方建议

要彻底解决此问题,唯一的办法是 消除服务器证书链中的 SHA-1 弱点

责任方解决方案官方建议/参考
服务器/运维升级证书链,使用 SHA-256 算法必须 确保所有服务器的 SSL/TLS 证书(包括服务器证书和中间 CA 证书)都使用 SHA-256 或更强的哈希算法签名。SHA-1 已被行业淘汰多年。
Android 客户端使用自动时间同步始终建议用户开启 “自动确定日期和时间” ,确保设备时间准确,这是避免因有效期检查失败引发一系列安全错误的最佳实践。
Android 客户端使用 Network Security Configuration (NSC)可以使用 NSC 配置文件来定义应用信任的 CA 集合、执行证书固定,或者配置 TLS 协议行为,从而更严格地控制安全连接。[2]

【DigiCert 证书提示】 您的日志中提到的 DigiCert Global Root CA 属于 G1 根证书体系,DigiCert 早就建议并推动用户迁移到 G2/G5 根证书,以确保使用最新的安全标准。请确保服务器使用的证书是基于这些新标准的。[3]