1. HTTPS基础与证书链验证

1.1 TLS握手协议流程

TLS(Transport Layer Security)握手是HTTPS建立安全通信通道的核心过程。客户端与服务端通过四次握手交换密钥材料,最终协商出会话密钥用于对称加密。握手阶段包含证书链下发与验证。

  • ClientHello:客户端发送支持的TLS版本、密码套件列表、随机数。
  • ServerHello:服务端选定TLS版本、密码套件,发送服务端随机数。
  • Certificate:服务端发送证书链(从服务器证书到根证书)。
  • ServerKeyExchange / CertificateRequest(可选):密钥协商或请求客户端证书。
  • ServerHelloDone:服务端完成握手消息发送。
  • ClientKeyExchange:客户端发送预主密钥(用服务端公钥加密)。
  • ChangeCipherSpec:双方切换为对称加密。
  • Finished:验证握手消息完整性。
证书验证时机:客户端收到Certificate消息后,立即对证书链执行完整性、有效期、吊销状态、域名匹配和签名验证。只有验证通过才能继续后续握手。

1.2 证书链结构与CA信任机制

数字证书遵循X.509 v3标准。一个完整的证书链通常由三级组成:

层级角色颁发者信任锚
叶子证书服务器证书中间CA非自签
中间CA证书桥梁根CA非自签
根CA证书信任锚自签名预置于信任存储

证书链验证遵循信任锚模型:从叶子向上追溯到系统或用户信任的根证书。每个证书的Subject与上一层Issuer必须匹配,签名合法,且在有效期内。

1.3 Android系统根证书存储

Android系统从版本4.0(API 14)起使用系统信任存储(System Trust Store),默认包含数百个知名根CA证书。存储位置:

  • /system/etc/security/cacerts/ —— 系统预置根证书(.0格式,基于OpenSSL哈希命名)。
  • /data/misc/user/0/cacerts-added/ —— 用户安装的自签或私有CA证书(仅影响当前用户,需用户确认)。

每个证书文件是一个PEM格式的公钥证书,文件名如 00673b5b.0。Android使用TrustManager API加载这些证书库。开发者可通过KeyStore或CertificateFactory读取。

注意:自Android 7.0(API 24)开始,默认不再信任用户安装的CA证书,仅信任系统CA。若需在调试代理(如Charles)中解密HTTPS流量,必须在network_security_config.xml中显式声明user-ca信任域。

1.4 实战:查看证书链与验证根证书

使用OpenSSL命令行工具可抓取服务器证书链并手动验证。例如连接www.google.com:

openssl s_client -showcerts -connect www.google.com:443 -servername www.google.com

输出会包含完整的证书链(每段-----BEGIN CERTIFICATE-----到-----END CERTIFICATE-----)。提取根证书后,可验证其摘要是否与Android系统预置根证书匹配:

openssl x509 -in rootCA.pem -hash -noout
# 输出形如 "00673b5b"
# 检查 /system/etc/security/cacerts/ 中是否存在同名 .0 文件

1.5 常见证书验证错误

错误原因Android异常表现解决方案
证书过期SSLHandshakeException + “Certificate expired”更新服务器证书
主机名不匹配SSLPeerUnverifiedException + “No name matching xxx”使用正确域名或配置HostnameVerifier
自签证书不在信任库SSLHandshakeException + “Trust anchor for certification path not found”安装自签CA到系统/用户信任存储
中间证书缺失同上服务端配置完整的证书链
Android 7+ 用户CA不生效调试代理抓包失败添加user-ca到network_security_config.xml

1.6 安全建议与性能优化

  • 证书固定(Pinning):在代码中固定叶子证书或中间CA公钥,防止证书擅自替换(第2章详述)。
  • 根证书存储更新:通过Google Play Services定期推送,但Android 7+已集成自动更新模块。
  • 减少握手延迟:使用TLS 1.3(0-RTT)、会话复用(Session Ticket)。
  • 避免吊销检查延迟:OCSP stapling需服务器支持;离线缓存CRL可能造成陈旧。

1.7 内联SVG:TLS握手与证书链验证流程

下图展示了TLS 1.2握手过程中,客户端接收证书链并向上验证至根CA的完整路径。

TLS握手与证书链验证流程 TLS 1.2 握手:证书链下发与验证 客户端 服务端 ClientHello (TLS版本, 密码套件, 随机数) ServerHello (选定版本/套件, 服务端随机数) Certificate (证书链:叶子→中间→根) ServerHelloDone 客户端验证证书链 1. 检查有效期 2. 域名匹配 3. 签名有效性 4. 回溯至信任根 根CA证书 中间CA证书 叶子(服务器)证书 信任锚 系统/用户信任存储中的 根CA证书(自签名)

1.8 本章小结

HTTPS证书链验证是Android安全通信的基石。理解TLS握手、证书链结构以及Android根证书存储机制,是后续实现证书固定(Pinning)与自定义网络库的基础。开发者应重点关注:

  • 证书链缺失是线上常见错误,需强制服务端配置完整链。
  • Android 7+ 用户CA隔离策略影响调试和私有CA部署。
  • 证书固定不能替代底层验证,但能极大增强防中间人攻击能力。