Android使用自签证书利用Okhttp进行HTTPS接口的安全连接

在上一篇文章【使用自签证书利用Okhttp进行HTTPS接口的安全连接】中,我们自己生成了证书,创建了最简单的接口,实现了让浏览器信任了我们的证书,那么,在Android上要怎么做呢?在android中,其实也是差不多的概念,android的app都会默认使用系统的受信任证书列表,
我们可以参考android官网https://developer.android.com/training/articles/security-config?hl=zh-cn#certificates里面的说明来学习,这个受信任列表是可以切换的,并且都有默认值

在这里插入图片描述

系统的受信任列表我们也可以在手机的设置里面找到,并且我们可以选择把一些证书让他失效,大家可以试试将上面的百度的根证书找到它让它失效后
在这里插入图片描述

再来看看手机浏览器里访问百度,你会发现百度也不信任了哈哈。

所以在Android上,套路是和我们Windows一样的,但是由于我们没法直接把我们的证书加入到系统里面,当然root的除外,所以我们只能使用另一种方式,即访问接口的时候,不使用系统的默认受信任列表,而是使用我们指定的证书来做验证,这边以okhttp来实现将证书植入到我们的app中,让我们的app可以使用自签证书实现https的通讯

创建okhttp client,我们还是使用以之前的go服务器为例,正常情况下的访问会是这样来使用

val client = OkHttpClient.Builder()
            .build()
val request: Request = Request.Builder()
.url("https://10.0.10.22:8081/ping")
.build()
Thread {
    client.newCall(request).execute()
    .use { response -> Log.d("MainActivity", "response str is '${response.body?.string()}'") }
}.start()

由于我们的证书手机上的受信任列表中肯定是不存在的,所以肯定会报错

在这里插入图片描述

这时候我们给okhttp配置ssl,来让okhttp使用我们自己的ssl规则和证书进行https连线,而不是使用默认的系统的受信任列表

这边我们将CA根证书放在了assets目录下,方便取出

在这里插入图片描述

模仿官网:https://developer.android.com/training/articles/security-ssl?hl=zh-cn#UnknownCa 的未知证书的用法,创建SSLSocketFactory和TrustManager

// Load CAs from an InputStream
// (could be from a resource or ByteArrayInputStream or ...)
val cf: CertificateFactory = CertificateFactory.getInstance("X.509")
val caInput: InputStream = BufferedInputStream(assets.open("rootca.crt"))
val ca: X509Certificate = caInput.use {
    cf.generateCertificate(it) as X509Certificate
}

// Create a KeyStore containing our trusted CAs
val keyStoreType = KeyStore.getDefaultType()
val keyStore = KeyStore.getInstance(keyStoreType).apply {
    load(null, null)
    setCertificateEntry("ca", ca)
}


val trustManagerFactory: TrustManagerFactory = TrustManagerFactory.getInstance(
    TrustManagerFactory.getDefaultAlgorithm()
)
trustManagerFactory.init(keyStore)
val trustManagers: Array<TrustManager> = trustManagerFactory.trustManagers
check(!(trustManagers.size != 1 || trustManagers[0] !is X509TrustManager)) {
    ("Unexpected default trust managers:"
            + trustManagers.contentToString())
}
val trustManager: X509TrustManager = trustManagers[0] as X509TrustManager

val sslContext: SSLContext = SSLContext.getInstance("TLS")
sslContext.init(null, arrayOf<TrustManager>(trustManager), null)
val sslSocketFactory: SSLSocketFactory = sslContext.socketFactory

然后在okhttp client上使用我们的SSLSocketFactory和TrustManager

val client = OkHttpClient.Builder()
            	.sslSocketFactory(sslSocketFactory, trustManager)
            	.build()

这边还需要注意的是,我们提到过证书中“Subject Alternative Name”这个字段,那么okhttp内部也会对这个字段进行验证,在connectTls方法中,会调用verify方法进行验证

在这里插入图片描述

hostnameVerifier有默认的实现类实现了默认的verify方法,其有一套默认的验证规则,会根据ip和hostname分别验证,

在这里插入图片描述

会使用getSubjectAltNames来获取证书中的Subject Alternative Name字段

在这里插入图片描述

所以,我们只要用上一篇文章的方法在证书中配置了正确的IP或者Hostname,那么就可以直接访问了,或者我们可以通过把默认的实现类进行覆盖,

val client = OkHttpClient.Builder()
            .sslSocketFactory(sslSocketFactory, trustManager)
            .hostnameVerifier { hostname, _ ->
                true
            }
            .build()

当然,这样做还是有一定风险的,所以还是推荐证书中写入Subject Alternative Name字段。

另外补充下,我们也是可以无条件的让okhttp信任所有证书来进行https连接,但是这样是非常危险的,所以不推荐这样处理。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

卡卡爾

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值