【发布时间】:2018-10-25 11:54:14
【问题描述】:
有时需要允许不安全的 HTTPS 连接,例如在一些应该适用于任何网站的网络爬虫应用程序中。我将 one such solution 与旧的 HttpsURLConnection API 一起使用,该 API 最近被 JDK 11 中的 new HttpClient API 取代。使用这个新 API 允许不安全的 HTTPS 连接(自签名或过期证书)的方法是什么?
UPD:我尝试过的代码(在 Kotlin 中但直接映射到 Java):
val trustAllCerts = arrayOf<TrustManager>(object: X509TrustManager {
override fun getAcceptedIssuers(): Array<X509Certificate>? = null
override fun checkClientTrusted(certs: Array<X509Certificate>, authType: String) {}
override fun checkServerTrusted(certs: Array<X509Certificate>, authType: String) {}
})
val sslContext = SSLContext.getInstance("SSL")
sslContext.init(null, trustAllCerts, SecureRandom())
val sslParams = SSLParameters()
// This should prevent host validation
sslParams.endpointIdentificationAlgorithm = ""
httpClient = HttpClient.newBuilder()
.sslContext(sslContext)
.sslParameters(sslParams)
.build()
但在发送时我有异常(尝试使用自签名证书在本地主机上):
java.io.IOException: No name matching localhost found
使用 IP 地址而不是 localhost 会出现“不存在主题替代名称”异常。
经过JDK的一些调试,我发现sslParams在抛出异常的地方确实被忽略了,并且使用了一些本地创建的实例。进一步调试显示,影响主机名验证算法的唯一方法是将jdk.internal.httpclient.disableHostnameVerification 系统属性设置为 true。这似乎是一个解决方案。上面代码中的SSLParameters 无效,因此可以丢弃这部分。使其仅在全局范围内可配置看起来像是新 HttpClient API 中的严重设计缺陷。
【问题讨论】:
-
你需要实例化一个
SSLContext,它会忽略坏证书,然后用它来建立连接。
标签: java java-11 java-http-client