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)

请点赞、收藏,感谢大家的支持

Android Studio中配置云端证书可以让你的应用程序与云服务进行安全通信。下面是一些步骤来配置Android Studio的云端证书: 1. 首先,你需要获取一个有效的证书文件。这个证书文件通常由你的云服务提供商提供,或者你可以自己生成。 2. 将证书文件保存到你的Android Studio项目的`res/raw`目录中。如果该目录不存在,你可以手动创建它。 3. 在`app`模块的`build.gradle`文件中添加以下代码,以将证书文件包含到你的应用程序中: ```groovy android { // ... // 在这里添加以下代码 packagingOptions { resources { srcDirs += ['src/main/res/raw'] exclude '**/.cert' } } } ``` 这段代码将告诉Android构建系统将`res/raw`目录中的证书文件包含到你的应用程序中,并排除`.cert`文件。 4. 现在你可以在代码中使用证书文件了。例如,如果你要使用HTTPS与云服务建立连接,可以在代码中使用以下示例: ```java try { CertificateFactory cf = CertificateFactory.getInstance("X.509"); InputStream certInputStream = getResources().openRawResource(R.raw.your_certificate); Certificate ca; try { ca = cf.generateCertificate(certInputStream); } finally { certInputStream.close(); } // 使用ca证书创建一个SSLContext实例,并将其应用于你的网络请求 SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(null, new TrustManager[]{new CustomTrustManager(ca)}, null); // 使用sslContext来创建你的网络请求 // ... } catch (Exception e) { e.printStackTrace(); } ``` 在这个示例中,我们使用了`CertificateFactory`类从证书文件中读取证书,并使用`SSLContext`类创建一个包含该证书的`SSLContext`实例,以便将其应用于网络请求。 这是一个简单的配置云端证书的方法,你可以根据你的具体需求来进行修改和扩展。希望对你有所帮助!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

薛瑄

文章不错,请博主吃包辣条

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

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

打赏作者

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

抵扣说明:

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

余额充值