一文解决Java中IP地址访问HTTPS接口的SSL证书验证问题

 更新时间:2025年12月19日 08:33:05   作者:一勺菠萝丶  
这篇文章主要为大家详细介绍了解决Java中IP地址访问HTTPS接口的SSL证书验证问题的相关知识,文中的示例代码讲解详细,感兴趣的小伙伴可以了解下

问题描述

在使用Java的RestTemplate访问HTTPS接口时,如果使用IP地址而不是域名,经常会遇到以下错误:

java.security.cert.CertificateException: No subject alternative names matching IP address 111.63.81.79 found
nested exception is javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: No subject alternative names matching IP address 111.63.81.79 found

奇怪的是:使用Postman、curl等工具可以正常访问,但Java代码却报错。

问题原因

SSL证书验证机制

HTTPS协议在建立连接时,会进行SSL证书验证,主要包括两个方面:

  • 证书有效性验证:检查证书是否过期、是否被吊销等
  • 主机名验证:检查证书中的域名或IP地址是否与访问的地址匹配

为什么Postman可以,Java不行

  • Postman:默认情况下,Postman可能会跳过某些SSL验证(特别是开发环境)
  • Java:Java的SSL验证非常严格,会检查证书的Subject Alternative Names (SAN)字段
  • 问题根源:当使用IP地址访问时,如果证书的SAN中没有包含该IP地址,Java就会拒绝连接

证书的Subject Alternative Names

SSL证书中有一个字段叫Subject Alternative Names (SAN),它列出了该证书可以用于哪些域名或IP地址。例如:

Subject Alternative Names:
    DNS: example.com
    DNS: www.example.com
    IP Address: 192.168.1.1

如果证书中没有包含你访问的IP地址(如111.63.81.79),Java就会抛出上述异常。

解决方案

方案概述

我们需要配置RestTemplate,让它跳过SSL证书验证。注意:这种方法只适用于开发/测试环境,生产环境应该使用正确的证书。

完整代码实现

创建一个RestTemplateConfig配置类:

package com.example.zbx.config;

import org.apache.http.client.config.RequestConfig;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.security.cert.X509Certificate;

/**
 * RestTemplate配置类
 * 配置忽略SSL证书验证,支持使用IP地址访问HTTPS接口
 * @author lxy
 */
@Configuration
public class RestTemplateConfig {

    /**
     * 创建RestTemplate Bean
     * 配置忽略SSL证书验证,支持使用IP地址访问HTTPS接口
     * @return RestTemplate实例
     */
    @Bean
    public RestTemplate restTemplate() {
        try {
            // 创建完全信任所有证书的TrustManager
            TrustManager[] trustAllCerts = new TrustManager[]{
                    new X509TrustManager() {
                        @Override
                        public X509Certificate[] getAcceptedIssuers() {
                            return null;
                        }

                        @Override
                        public void checkClientTrusted(X509Certificate[] certs, String authType) {
                            // 不进行任何检查,信任所有客户端证书
                        }

                        @Override
                        public void checkServerTrusted(X509Certificate[] certs, String authType) {
                            // 不进行任何检查,信任所有服务器证书
                        }
                    }
            };

            // 创建SSL上下文,使用自定义的TrustManager
            SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(null, trustAllCerts, new java.security.SecureRandom());

            // 创建SSL连接工厂,忽略主机名验证(包括IP地址验证)
            SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(
                    sslContext,
                    NoopHostnameVerifier.INSTANCE
            );

            // 创建请求配置
            RequestConfig requestConfig = RequestConfig.custom()
                    .setConnectTimeout(10000)  // 连接超时10秒
                    .setConnectionRequestTimeout(10000)  // 请求超时10秒
                    .setSocketTimeout(30000)  // 读取超时30秒
                    .build();

            // 创建HttpClient
            CloseableHttpClient httpClient = HttpClients.custom()
                    .setSSLSocketFactory(sslSocketFactory)
                    .setDefaultRequestConfig(requestConfig)
                    .evictExpiredConnections()
                    .evictIdleConnections(30, java.util.concurrent.TimeUnit.SECONDS)
                    .build();

            // 创建请求工厂
            HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
            factory.setHttpClient(httpClient);
            factory.setConnectTimeout(10000);
            factory.setConnectionRequestTimeout(10000);
            factory.setReadTimeout(30000);

            // 创建RestTemplate
            return new RestTemplate(factory);
        } catch (Exception e) {
            throw new RuntimeException("创建RestTemplate失败", e);
        }
    }
}

关键点说明

1. 自定义TrustManager

TrustManager[] trustAllCerts = new TrustManager[]{
    new X509TrustManager() {
        @Override
        public void checkServerTrusted(X509Certificate[] certs, String authType) {
            // 不进行任何检查,信任所有服务器证书
        }
        // ... 其他方法
    }
};

这个X509TrustManager会跳过所有证书验证,包括:

  • 证书是否过期
  • 证书是否被吊销
  • 证书的域名/IP是否匹配

2. 创建SSL上下文

SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, trustAllCerts, new java.security.SecureRandom());

使用自定义的TrustManager初始化SSL上下文。

3. 忽略主机名验证

SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(
    sslContext,
    NoopHostnameVerifier.INSTANCE  // 不验证主机名
);

NoopHostnameVerifier.INSTANCE会跳过主机名验证,这样即使证书中没有对应的IP地址也能通过验证。

Maven依赖

确保你的pom.xml中包含以下依赖:

<!-- HttpClient4 (for RestTemplate SSL configuration) -->
<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
</dependency>

使用示例

配置完成后,直接使用RestTemplate即可,无需额外代码:

@Autowired
private RestTemplate restTemplate;

public void callApi() {
    String url = "https://111.63.81.79:10091/api/endpoint";
    ResponseEntity<String> response = restTemplate.postForEntity(url, request, String.class);
    // 处理响应...
}

注意事项

安全警告

  • 仅用于开发/测试环境:跳过SSL验证会带来安全风险,生产环境不应该使用
  • 中间人攻击风险:攻击者可以伪造证书,你的应用无法识别
  • 数据泄露风险:无法保证连接的安全性

生产环境建议

如果必须在生产环境使用,建议:

  • 使用正确的证书:让服务器提供包含IP地址的证书
  • 配置证书信任:只信任特定的证书颁发机构(CA)
  • 使用域名访问:尽量使用域名而不是IP地址

示例:生产环境的正确做法

// 只信任特定的证书
KeyStore trustStore = KeyStore.getInstance("JKS");
trustStore.load(new FileInputStream("truststore.jks"), "password".toCharArray());

TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("X509");
trustManagerFactory.init(trustStore);

SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, trustManagerFactory.getTrustManagers(), null);

常见问题

Q1: 为什么之前可以,现在不行了?

可能的原因:

  • Java版本更新,SSL验证更严格了
  • 服务器证书更新了,新证书没有包含IP地址
  • 网络环境变化,使用了不同的IP地址

Q2: 有没有更简单的办法?

对于开发环境,可以设置JVM参数(不推荐):

-Dcom.sun.net.ssl.checkRevocation=false

但这种方法不够灵活,建议使用配置类的方式。

Q3: 会影响其他HTTP请求吗?

不会。这个配置只影响使用RestTemplate的HTTPS请求,HTTP请求不受影响。

Q4: 如何验证配置是否生效?

在代码中添加日志,观察是否还有证书验证错误:

log.info("RestTemplate配置完成,SSL验证已禁用");

如果不再出现CertificateException,说明配置生效了。

总结

  • 问题根源:Java的SSL验证严格,证书中没有IP地址时会拒绝连接
  • 解决方案:配置RestTemplate跳过SSL证书验证
  • 关键代码:自定义X509TrustManager + NoopHostnameVerifier
  • 安全提醒:仅用于开发/测试环境,生产环境应使用正确的证书

到此这篇关于一文解决Java中IP地址访问HTTPS接口的SSL证书验证问题的文章就介绍到这了,更多相关Java解决SSL证书验证问题内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java如何修改.class文件变量

    Java如何修改.class文件变量

    这篇文章主要介绍了Java如何修改.class文件变量,帮助大家更好的理解和学习Java,感兴趣的朋友可以了解下
    2020-09-09
  • Java利用钉钉机器人实现发送群消息

    Java利用钉钉机器人实现发送群消息

    这篇文章主要为大家详细介绍了Java语言如何通过钉钉机器人发送群消息通知,文中的示例代码讲解详细,感兴趣的小伙伴可以了解一下
    2022-09-09
  • 使用Spring Batch实现大数据处理的操作方法

    使用Spring Batch实现大数据处理的操作方法

    通过使用Spring Batch,我们可以高效地处理大规模数据,本文介绍了如何配置和实现一个基本的Spring Batch作业,包括读取数据、处理数据和写入数据的全过程,感兴趣的朋友跟随小编一起看看吧
    2024-07-07
  • java通过cglib动态生成实体bean的操作

    java通过cglib动态生成实体bean的操作

    这篇文章主要介绍了java通过cglib动态生成实体bean的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-02-02
  • Java 8函数式接口之BinaryOperator使用示例详解

    Java 8函数式接口之BinaryOperator使用示例详解

    这篇文章主要大家介绍了Java 8函数式接口之BinaryOperator,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-07-07
  • Spring oxm入门实例

    Spring oxm入门实例

    这篇文章主要介绍了Spring oxm入门实例,具有一定借鉴价值,需要的朋友可以参考下
    2017-12-12
  • java -jar example.jar 产生的日志输出到指定文件的方法

    java -jar example.jar 产生的日志输出到指定文件的方法

    这篇文章给大家介绍java -jar example.jar 产生的日志输出到指定文件的方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,感兴趣的朋友一起看看吧
    2025-08-08
  • idea64.exe.vmoptions文件如何设置调整VM配置文件

    idea64.exe.vmoptions文件如何设置调整VM配置文件

    这篇文章主要介绍了idea64.exe.vmoptions文件如何设置调整VM配置文件问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-04-04
  • java 实现文件编码检测的几种方式汇总

    java 实现文件编码检测的几种方式汇总

    在实际开发中,我们常常涉及某些场景需要对文件的读取,但是因为不知道具体的编码格式,导致读取到的文件内容乱码,因此在读取文件内容之前,需要解析获取文件的编码,这样读取的内容就不会出现乱码了,下面是常见的几种获取文件编码的方式,感兴趣的朋友一起看看吧
    2025-09-09
  • Java实现字符串匹配的示例代码

    Java实现字符串匹配的示例代码

    这篇文章主要介绍了Java实现字符串匹配,本文通过示例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-04-04

最新评论