文档中心
OKHttp娣诲姞SSL璇佷功鍏ㄦ敾鐣ヤ粠鍘熺悊鍒板疄鎴樿瑙?txt
时间 : 2025-09-27 16:28:11浏览量 : 2

在移动开发和安全通信中,HTTPS已成为数据传输的标配。但若服务器使用自签名证书或私有CA证书,客户端默认会因证书不信任而报错。这时就需要通过OKHttp添加SSL证书来建立安全连接。本文将以“手把手”方式,带你理解原理并完成实操。
一、为什么要手动添加SSL证书?
当OKHttp访问HTTPS接口时,默认会校验服务器证书的合法性(比如是否为权威CA签发、域名是否匹配等)。但以下场景需手动处理证书:
1. 自签名证书:内网测试环境常用自签证书,浏览器会提示“不安全”,代码直接请求会抛出`SSLHandshakeException`。
2. 私有CA机构:企业内部分发的私有根证书(如公司内部的CA),设备默认不信任。
3. 证书固定(Pinning):防止中间人攻击,强制校验服务器证书指纹。
举例:
假设你公司测试环境域名是 `https://test-api.com`,使用自签证书。直接用OKHttp请求会报错:
```java
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder().url("https://test-api.com").build();
// 抛出异常: javax.net.ssl.SSLHandshakeException: Certificate chain not trusted
```
二、解决方案分步指南
方案1:绕过验证(仅限测试环境)
适用于快速调试,但存在安全风险:
OkHttpClient client = new OkHttpClient.Builder()
.hostnameVerifier((hostname, session) -> true) // 跳过域名验证
.sslSocketFactory(getInsecureSSLSocketFactory(), getInsecureTrustManager())
.build();
// 创建信任所有证书的TrustManager
private static X509TrustManager getInsecureTrustManager() {
return new X509TrustManager() {
@Override public void checkClientTrusted(X509Certificate[] chain, String authType) {}
@Override public void checkServerTrusted(X509Certificate[] chain, String authType) {}
@Override public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; }
};
}
?? 注意:此代码允许中间人攻击,严禁生产环境使用!
方案2:加载指定证书(推荐)
通过将证书文件(如`.crt`或`.pem`)放入`assets`目录,显式信任它:
1. 准备证书文件
假设你的证书文件是 `my_certificate.crt`,将其放入Android项目的`assets/ssl/`目录。
2. 代码实现
// 从assets读取证书
private SSLSocketFactory createSSLSocketFactory(Context context) {
try {
CertificateFactory cf = CertificateFactory.getInstance("X.509");
InputStream certInput = context.getAssets().open("ssl/my_certificate.crt");
Certificate ca = cf.generateCertificate(certInput);
// 创建KeyStore并加载证书
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null, null);
keyStore.setCertificateEntry("ca", ca);
// 初始化TrustManagerFactory
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(keyStore);
// 创建SSLContext
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, tmf.getTrustManagers(), null);
return sslContext.getSocketFactory();
} catch (Exception e) {
throw new RuntimeException(e);
}
// 构建OKHttpClient
.sslSocketFactory(createSSLSocketFactory(context), getTrustManager(keyStore))
方案3:动态下发更新(高级场景)
大型App可能遇到根证书记录过期的情况。此时可通过网络接口动态更新客户端信任的根证书记录:
1. 后端提供API返回最新的根证书记录(Base64编码)
2. 客户端解析并替换旧的信任链
String dynamicCertData = "..."; // 从API获取的PEM格式内容
X509Certificate cert = (X509Certificate) CertificateFactory.getInstance("X.509")
.generateCertificate(new ByteArrayInputStream(dynamicCertData.getBytes()));
三、最佳实践与安全建议
1. 区分环境配置
- 开发环境:可临时绕过验证
- 生产环境:严格校验+考虑双向TLS
2. 启用HSTS和HPKP增强防护
3. 监控异常日志
```java
client.eventListener(new EventListener() {
@Override public void callFailed(Call call, IOException e) {
if (e instanceof SSLHandshakeException) {
//上报到监控系统!
}
}
});
```
4. 定期审计依赖库漏洞
```groovy
// build.gradle中检查OKhttp版本是否含已知漏洞
implementation 'com.squareup.okhttp3:okhttp:4.x.x'
FAQ速查表
Q: OKhttp4和OKhttp3的API有区别吗?
A: v4.x开始移除了过时的API(如直接设置`HostnameVerifier`),建议用新的构建方式。
Q: iOS的AFNetworking如何实现类似功能?
A: iOS需通过`AFSecurityPolicy`设置`pinnedCertificates`.
Q: Charles抓包工具为什么能解密HTTPS?
A: Charles会向设备安装自己的根证书记录——这正是我们通过方案2防御的行为!
通过以上方法,你可以灵活应对各类HTTPS场景需求。记住:“安全无小事”,正确处理SSL/TLS是保护用户数据的第一道防线!
TAG:okhttp添加ssl证书,okhttp配置https,okhttp请求https,okhttp教程