我有一个spring-boot应用程序(版本2.3.7),它使用okhttp3,并且我正在尝试在https://test.server.com:8888/api
中调用一个api。服务器上的证书是自签名的,所以我更新了我的插入符号以信任这个证书。当我像这样运行SSLPoke.class时,我得到的是Successfully Connected
。但是当请求从我的应用程序发出时,我得到了javax.net.ssl.SSLPeerUnverifiedException: Hostname test.server.com not verified:
错误。由于cacerts已更新,我是否需要编写额外的代码来验证主机名?
更具体地说,我有以下代码片段。如果我在VM选项-Djavax.net.ssl.trustStore=client-truststore.jks -Djavax.net.ssl.trustStorePassword=changeit
中传递了信任库,则使用okhttp的调用将失败,但使用rest模板的调用将成功。
@SpringBootApplication
public class DemoOkhttpClientApplication implements CommandLineRunner {
public static void main(String[] args) {
SpringApplication.run(DemoOkhttpClientApplication.class, args);
}
@Override
public void run(String... args) throws Exception {
try {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://localhost:8443/")
.addConverterFactory(MoshiConverterFactory.create())
.build();
TestClient testClient = retrofit.create(TestClient.class);
System.out.println(String.format("OkHttp Response %s", testClient.callTestEndpoint().execute().body()));
} catch (Exception ex){
System.err.println();
System.err.println("Ok Http error " + ex.getMessage());
}
try {
RestTemplate restTemplate = new RestTemplate();
System.out.println(String.format("Rest Template Response %s",
restTemplate.exchange("https://localhost:8443/test", HttpMethod.GET, null, String.class)));
} catch (Exception ex){
System.err.println("Rest Template error" + ex.getMessage());
}
}
}
interface TestClient {
@GET("/test")
Call<String> callTestEndpoint();
}
上述代码片段的输出如下所示
Ok Http error Hostname localhost not verified:
certificate: sha256/INkKXJiMFIGNnvE5ga1Ye0KjxjP5jO9hIrNvQs4wuU0=
DN: CN=localhost, OU=PC, O=PC, L=Marousi, ST=Athens, C=GR
subjectAltNames: []
Rest Template Response <200,Ok,[Content-Type:"text/plain;charset=UTF-8", Content-Length:"2", Date:"Thu, 11 Feb 2021 17:09:55 GMT", Keep-Alive:"timeout=60", Connection:"keep-alive"]>
发布于 2021-02-12 17:16:53
我怀疑这是因为您生成的证书无效,CN不应该再用于主机名验证。证书中的subjectAltNames为空。这在3.10.0中发生了变化
https://square.github.io/okhttp/changelog_3x/#version-3100
新特性:不再依赖于主机名的通用名称(CN)验证。此行为已于2000年5月在RFC 2818中弃用,并于最近从主要web浏览器中删除。
如果您只想将一个devserver列入白名单,您可以使用以下命令
https://square.github.io/okhttp/changelog/#version-470
val clientCertificates = HandshakeCertificates.Builder()
.addPlatformTrustedCertificates()
.addInsecureHost("localhost")
.build()
val client = OkHttpClient.Builder()
.sslSocketFactory(clientCertificates.sslSocketFactory(), clientCertificates.trustManager)
.build()
发布于 2021-02-12 04:10:00
显然,唯一的方法是让OkHttp忽略主机名验证
OkHttpClient okHttpClient = new OkHttpClient.Builder().hostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
}).build();
Retrofit retrofit = new Retrofit.Builder()
.client(okHttpClient)
.baseUrl("https://localhost:8443/")
.addConverterFactory(MoshiConverterFactory.create())
.build();
https://stackoverflow.com/questions/66152780
复制相似问题