Android7.0 网络安全配置、自定义okhttp证书 ——解决HTTPs 抓包问题

Android7.0 HTTPs 抓包问题

很多小伙伴,遇到在Android7.0 开发APP遇到无法抓包的问题,如果是配置了Network security configuration,可以加一行代码就可以解决

在Android7.0及以上的系统中,每个应用可以定义自己的可信CA集集。

默认情况下,应用只会信任系统预装的CA证书,而不会信任用户安装的CA证书。

而回想我们抓包的过程,无论是fiddler还是Charles,想抓https,都必须手机安装对应的证书,通过fiddler/Charles安装的证书恰恰正属于用户安装的CA证书,因此会被视作不安全的证书。

解决办法有两种:

1、配置network-security-config.xml 信任用户安装的证书

所以需要在network-security-config.xml 设置信任用户安装的证书

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <base-config cleartextTrafficPermitted="false">

    </base-config>

    <debug-overrides>
        <trust-anchors>
            <certificates src="system" overridePins="true" />
            //主要是这行代码
            <certificates src="user" overridePins="true" />
        </trust-anchors>
    </debug-overrides>
</network-security-config>

更多使用,查看Network security configuration

2、 自定义https 请求的证书

下面给出OkHttp 自定义证书的工具类

工具类

下面是工具类,只需要传入OkHttpClient.Builder对象,在使用中传入this 和自定义证书的路径(assets 资源下面的路径)

/**
 * @Author: xuexuan: 2019年5月24日19:49:10
 * @Description:设置okhttp 自定义证书
 */


fun OkHttpClient.Builder.sslSocketFactory(builder: OkHttpClient.Builder, path: String): OkHttpClient.Builder {
    val sslUtil: SSLUtil = SSLUtil()
    sslUtil.addCertificate(path, context)
    builder.sslSocketFactory(sslUtil.getSSLSocketFactory(), sslUtil.mX509TrustManager)
    return builder
}

class SSLUtil {

    val mX509TrustManager = getTrustManager()

    // 证书数据
    private var CERTIFICATES_DATA = ArrayList<ByteArray?>()


    /**
     * 添加https证书
     *
     * @param inputStream
     */
    @Synchronized
    fun addCertificate(path: String, context: Context) {

        val inputStream = context.assets.open(path)

        try {
            var len = 0// 数据总长度
            val data = ArrayList<ByteArray>()
            var ava = inputStream.available() // 数据当次可读长度
            while (ava > 0) {
                val buffer = ByteArray(ava)
                inputStream.read(buffer)
                data.add(buffer)
                len += ava
                ava = inputStream.available()
            }

            val buff = ByteArray(len)
            var dstPos = 0
            for (bytes in data) {
                val length = bytes.size
                System.arraycopy(bytes, 0, buff, dstPos, length)
                dstPos += length
            }

            CERTIFICATES_DATA.add(buff)
        } catch (e: IOException) {
            e.printStackTrace()
        }
    }


    /**
     * 获取sslSocketFactory() 中需要的参数  X509TrustManager
     */
    private fun getTrustManager(): X509TrustManager {

        val trustManagerFactory = TrustManagerFactory.getInstance(
                TrustManagerFactory.getDefaultAlgorithm());
        trustManagerFactory.init(getKeyStore())
        val trustManagers = trustManagerFactory.trustManagers;
        if (trustManagers.size != 1 || trustManagers[0] !is X509TrustManager) {
            throw  IllegalStateException("Unexpected default trust managers:"
                    + Arrays.toString(trustManagers))
        }
        return trustManagers[0] as X509TrustManager

    }


    /**
     * 获取sslSocketFactory() 中需要的参数  SSLSocketFactory
     */
    fun getSSLSocketFactory(): SSLSocketFactory {
        val sslContext = SSLContext.getInstance("TLS")
        sslContext.init(null, arrayOf(mX509TrustManager), null)
        return sslContext.socketFactory
    }


    private fun getKeyStore(): KeyStore {

        // 添加证书
        val certificates = ArrayList<InputStream>()

        // 将字节数组转为输入流数组
        if (CERTIFICATES_DATA.isNotEmpty()) {
            for (bytes in CERTIFICATES_DATA) {
                certificates.add(ByteArrayInputStream(bytes))
            }
        }


        val certificateFactory = CertificateFactory.getInstance("X.509")
        val keyStore = KeyStore.getInstance(KeyStore.getDefaultType())
        keyStore.load(null)
        try {
            var i = 0
            val size = certificates.size
            while (i < size) {
                val certificate = certificates[i]
                val certificateAlias = Integer.toString(i++)
                keyStore.setCertificateEntry(certificateAlias, certificateFactory
                        .generateCertificate(certificate))
                certificate?.close()
            }
        } catch (e: IOException) {
            e.printStackTrace()
        }

        return keyStore
    }
    
}

使用示例

Retrofit.Builder()
            .client(OkHttpClient.Builder()
                    .connectTimeout(30, TimeUnit.SECONDS)
                    .readTimeout(30, TimeUnit.SECONDS)
                    .writeTimeout(30, TimeUnit.SECONDS)
                    //这里使用的是kotlin的扩展函数,传入this,和assets 路径下的证书路径即可
                    .sslSocketFactory(this,"cers/FiddlerRoot.cer")
                    .build())
            .baseUrl(BuildConfig.API_HOST)
            .addConverterFactory(GsonConverterFactory.create())
            .build()
            .create(OwnerService::class.java)
发布了242 篇原创文章 · 获赞 775 · 访问量 224万+

猜你喜欢

转载自blog.csdn.net/xx326664162/article/details/90522181