如何在不重建客户端的情况下动态地将多个客户端证书应用到OkHttp Client

发布于 2025-01-13 15:16:31 字数 2778 浏览 3 评论 0原文

我有一个 Android 应用程序,应该能够分别使用不同的客户端证书连接到多个服务器。

将多个客户端证书动态添加到 OkHttp 客户端的正确方法是什么?

目前,当我应用新证书时,我正在调用此自定义方法:

private fun applyCertificate(certificatePath: String, password: String) {
    // load certificate into KeyStore
    FileInputStream(path).use {
      clientKeyStore.load(it, password.toCharArray())
    }
    // load KeyStore into KeyManagerFactory
    val keyManagerFactory = KeyManagerFactory.getInstance("X509")
    keyManagerFactory.init(clientKeyStore, null)
    // Initialize the SSL Context
    sslContext.init(keyManagerFactory.keyManagers, tmf.trustManagers, SecureRandom())
    
    // call newBuilder and set new socketFactory
    okHttpClient = okHttpClient.newBuilder()
      .sslSocketFactory(sslContext.socketFactory, tmf.trustManagers[0] as X509TrustManager)
      .build()
  }

我关心的是,

  • 当我动态添加多个证书时,我将多次将新的 SSLSocketFactory 设置到 OkHttpClient 中,这样安全吗?做?

我不确定是否有更好的方法可以在不重建 OkHttpClient 的情况下执行此操作。

我确实注意到有一个库 okhttp-tls,对于这种配置来说,这是一个更好的库吗?

编辑:

只是为了澄清一下,

当我创建应用程序时,我正在初始化 okHttpClient 的全局实例。在应用程序的生命周期中,多个应用程序组件可以同时使用此全局实例。

fun initialSetup() {
  okHttpClient = OkHttpClient.Builder().build()
  ...
}

然后我收到一个需要证书身份验证的安全请求:

val call = okHttpClient.newCall(
  Request.Builder().url("https://pki.service.com/resource1")
    .build()
)
val httpResponse = call.execute()

....

if (httpResponse.code == HTTP_CERTIFICATE_AUTHENTICATION) {
  val certificate = getCertificatePathForServer()

  httpClient.applyCertificate(certificate.path, certificate.password)
  ...
  // retry call
}

并且 applyCertificate() 看起来像我上面解释的

private fun applyCertificate(certificatePath: String, password: String) {
    // load certificate into KeyStore
    FileInputStream(path).use {
      clientKeyStore.load(it, password.toCharArray())
    }
    // load KeyStore into KeyManagerFactory
    val keyManagerFactory = KeyManagerFactory.getInstance("X509")
    keyManagerFactory.init(clientKeyStore, null)
    // Initialize the SSL Context
    sslContext.init(keyManagerFactory.keyManagers, tmf.trustManagers, SecureRandom())

    // call newBuilder and set new socketFactory
    okHttpClient = okHttpClient.newBuilder()
      .sslSocketFactory(sslContext.socketFactory, tmf.trustManagers[0] as X509TrustManager)
      .build()
  }

那样:我的问题是,每次添加新证书时,我都会重新构建 OkHttpClient,当前使用的组件全局 OkHttpClient 实例可能会出现不需要的副作用,例如挂起的请求未完成或更糟的是崩溃。重建当前可能与 okHttpClient.newBuilder() 一起使用的 OkHttpClient 实例是否安全?

I have an Android application that should be able to connect to multiple servers with different client certificates respectively.

What is the proper way to dynamically add multiple client certificates to OkHttp client?

Currently, when I apply a new Certificate I am calling this custom method:

private fun applyCertificate(certificatePath: String, password: String) {
    // load certificate into KeyStore
    FileInputStream(path).use {
      clientKeyStore.load(it, password.toCharArray())
    }
    // load KeyStore into KeyManagerFactory
    val keyManagerFactory = KeyManagerFactory.getInstance("X509")
    keyManagerFactory.init(clientKeyStore, null)
    // Initialize the SSL Context
    sslContext.init(keyManagerFactory.keyManagers, tmf.trustManagers, SecureRandom())
    
    // call newBuilder and set new socketFactory
    okHttpClient = okHttpClient.newBuilder()
      .sslSocketFactory(sslContext.socketFactory, tmf.trustManagers[0] as X509TrustManager)
      .build()
  }

My concern is

  • When I add multiple certificates dynamically, I will be setting a new SSLSocketFactory into the the OkHttpClient multiple times, is this safe to do?

I am not sure if there are better ways of doing this without rebuilding the OkHttpClient.

I did notice that there's the library okhttp-tls, is this a better library for this kind of configuration?

Edit:

Just to clarify,

I am initializing a global instance of okHttpClient when I create our application. This global instance may be used by multiple application components simultaneously for the lifetime of the application.

fun initialSetup() {
  okHttpClient = OkHttpClient.Builder().build()
  ...
}

then I get an a secured request that needs Certificate authentication:

val call = okHttpClient.newCall(
  Request.Builder().url("https://pki.service.com/resource1")
    .build()
)
val httpResponse = call.execute()

....

if (httpResponse.code == HTTP_CERTIFICATE_AUTHENTICATION) {
  val certificate = getCertificatePathForServer()

  httpClient.applyCertificate(certificate.path, certificate.password)
  ...
  // retry call
}

and applyCertificate() looks like I explained above:

private fun applyCertificate(certificatePath: String, password: String) {
    // load certificate into KeyStore
    FileInputStream(path).use {
      clientKeyStore.load(it, password.toCharArray())
    }
    // load KeyStore into KeyManagerFactory
    val keyManagerFactory = KeyManagerFactory.getInstance("X509")
    keyManagerFactory.init(clientKeyStore, null)
    // Initialize the SSL Context
    sslContext.init(keyManagerFactory.keyManagers, tmf.trustManagers, SecureRandom())

    // call newBuilder and set new socketFactory
    okHttpClient = okHttpClient.newBuilder()
      .sslSocketFactory(sslContext.socketFactory, tmf.trustManagers[0] as X509TrustManager)
      .build()
  }

My corcern is that as I am rebulding the OkHttpClient everytime I add a new certificate, components that currently use the global OkHttpClient instance might see undesired side effects, for example pending requests not completing or worse, crashing. Is it safe to rebuild an OkHttpClient instance that may currently be in use with okHttpClient.newBuilder()?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

眼泪淡了忧伤 2025-01-20 15:16:31

我确实注意到有一个库 okhttp-tls,对于这种配置来说,这是一个更好的库吗?

是的,该库非常适合于此。


HandshakeCertificates clientCertificates = new HandshakeCertificates.Builder()
    .addTrustedCertificate(...))
    .build();
OkHttpClient client = new OkHttpClient.Builder()
    .sslSocketFactory(clientCertificates.sslSocketFactory(), clientCertificates.trustManager())
    .build();

I did notice that there's the library okhttp-tls, is this a better library for this kind of configuration?

Yes, that library is well suited to this.


HandshakeCertificates clientCertificates = new HandshakeCertificates.Builder()
    .addTrustedCertificate(...))
    .build();
OkHttpClient client = new OkHttpClient.Builder()
    .sslSocketFactory(clientCertificates.sslSocketFactory(), clientCertificates.trustManager())
    .build();

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文