最近工作需要,手写了一个双向认证库,可以用在Java、Android上,不限于PC/手机、车载平台。首先我们来看看双向认证的原理机框架设计思路,最后会给出下载链接大家可以体验或者源码参考。
因为可以和FlexNet网络库(参考我写的网络库:文章链接)搭配使用,所以这里我也称之为Flex双向认证。
原理
Flex双向认证
是基于标准的HTTPS
进行的安全认证。在说 双向认证
之前,我们需要了解标准的HTTPS
;要了解HTTPS
我们先要了解 HTTP
,因为 HTTP
是 HTTPS
通讯的基础。
HTTP(HyperText Transport Protocol)超文本传输协议,它用于传输客户端和服务器端的数据。
HTTP标准交互流程
不难看出HTTP
使用很简单也很方便,但却存在以下 3 个致命问题:
- 使用明文通讯,内容可以被窃听。
- 不验证通讯方的真实身份,可能会遭到伪装。
- 无法证明报文的完整性,很容易被篡改。
HTTPS通信
HTTPS
是针对以上问题在HTTP
协议的基础上添加了加密机制 的通信方案。根据需求,主要分为单向认证
和双向认证
。
单向认证
单向认证的过程,客户端对服务器端下发的服务器端公钥证书进行验证,然后建立安全通信通道。
双向认证
双向通信流程,客户端除了需要对服务器端下发的服务器公钥证书进行验证外,还需要把客户端的公钥证书上传到服务器端给服务器端进行验证。等双方都认证通过了,才开始建立安全通信通道进行数据传输。
Flex双向认证
Flex库
选取了安全性更高的双向认证
方案。并进一步对证书安全性进行了处理。
资源配置
APP需要从车机端获取到对应的证书,才能进行双向认证下一步的逻辑。
统一的SSLLib
为了避免各个APP都需要单独去开发一套双向认证的方案,现实现了一套Flex双向认证
工具库。
获取车机资源进行认证
构建双向认证需要的对象HttpsUtils.buildSSL
,此方法是异步回调,一定要等到回调才能进行双向认证的后续逻辑。
/**
* 构建ssl认证
* 如果是在Application中调用,需要注意配置在主进程中使用,防止多进程导致异常
*
* @param ctx 获取车机端内置资源需要使用context
* @param callback 回调双向认证所需要的资源,为null表示构建失败
* */
private fun buildCarSSL() {
HttpsUtils.buildSSL(this) {
mCarParams = it
Log.e("SSL", "buildCarSSL:${it == null}")
}
}
在OKHTTP中配置双向认证
/**
* 创建默认的OkHttpClient
* 和服务器协 信息
* */
private fun buildOkHttpClient(): OkHttpClient {
val clientBuilder = OkHttpClient.Builder()
// 构建的双向认证对象 SSLParams
if (MainActivity. mCarParams != null) {
val ssl = MainActivity. mCarParams !!
clientBuilder.sslSocketFactory(ssl.sslSocketFactory, ssl.trustManager)
}
//不校验host;如果需要检验host,可以针对自己需要调用的服务器进行hostname比对
clientBuilder.hostnameVerifier { hostname, session -> true }
mInterceptors.forEach {
clientBuilder.addInterceptor(it)
}
if (BuildConfig.DEBUG) {//打印调试日志
val httpLoggingInterceptor = HttpLoggingInterceptor()
httpLoggingInterceptor.level = HttpLoggingInterceptor.Level.BODY
clientBuilder.addInterceptor(httpLoggingInterceptor)
}
clientBuilder.connectTimeout(OkHttpConst.CONNECT_TIME, TimeUnit.SECONDS)
clientBuilder.readTimeout(OkHttpConst.READ_TIME, TimeUnit.SECONDS)
return clientBuilder.build()
}
自定义资源进行认证
构建双向认证需要的对象SSLUtils.getDoubleSslFactory
。
/**
* TODO: demo调试的证书配置,对应的服务器是demo的测试云端;如果需要自己进行测试,需要使用自己的云端配置和修改
* @see LocalSSLApiStore.baseUrl
* */
private fun buildLocalSSL() {
val caIs = assets.open("ca-cert.pem")
val clientPfxIs = assets.open("client.p12")
val clientPsd = "hbzq253503125"
// mSSLParams = SSLUtils.getSingleSslFactory(
// arrayOf(caIs)
//