首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何避免javax.net.ssl.SSLPeerUnverifiedException:未验证主机名test.server.com

如何避免javax.net.ssl.SSLPeerUnverifiedException:未验证主机名test.server.com
EN

Stack Overflow用户
提问于 2021-02-11 18:20:32
回答 2查看 710关注 0票数 1

我有一个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模板的调用将成功。

代码语言:javascript
运行
复制
@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();
}

上述代码片段的输出如下所示

代码语言:javascript
运行
复制
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"]>
EN

回答 2

Stack Overflow用户

发布于 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

代码语言:javascript
运行
复制
val clientCertificates = HandshakeCertificates.Builder()
    .addPlatformTrustedCertificates()
    .addInsecureHost("localhost")
    .build()

val client = OkHttpClient.Builder()
    .sslSocketFactory(clientCertificates.sslSocketFactory(), clientCertificates.trustManager)
    .build()
票数 3
EN

Stack Overflow用户

发布于 2021-02-12 04:10:00

显然,唯一的方法是让OkHttp忽略主机名验证

代码语言:javascript
运行
复制
 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();
票数 -2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/66152780

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档