Jersey调用外部API遇SSL证书匹配错误,如何禁用SSL校验?
问题描述
我正尝试通过Java应用调用外部API,使用Jersey发起请求,代码如下:
ClientConfig clientConfig = new ClientConfig(); //Open Digest authentication clientConfig.register(JacksonFeature.class); //Create new rest client Client client = ClientBuilder.newClient( clientConfig ); //Set the url WebTarget webTarget = client.target(rootUrl); Invocation.Builder invocationBuilder = webTarget.request(javax.ws.rs.core.MediaType.APPLICATION_JSON); MultivaluedMap<String, Object> header = new MultivaluedHashMap<>(); header.add("UserName", username); header.add("Password", password); invocationBuilder.headers(header); logger.info("Initialisation of cashout service successful"); // create request Gson gson = new Gson(); String transactionString = gson.toJson(request); try { // start the response Response response = invocationBuilder.put(Entity.entity(transactionString, javax.ws.rs.core.MediaType.APPLICATION_JSON)); //We check if the response is ok if(response.getStatus() == 200) { logger.info("The paiement is done, we got 200 code return"); responseData = response.readEntity(AirtimePaymentResponse.class); logger.info("the response data is {} ", responseData); }else { logger.info("error during the paiement"); throw new GGException("Error during the paiement", HttpStatus.valueOf(response.getStatus())); } }catch (Exception e) { throw new GGException(e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR); }
但遇到错误:javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: No subject alternative DNS name matching xxx.com found。请问如何在代码中禁用SSL校验以运行在不安全模式?我尝试了多种方案但均未成功,恳请解答。
解决方案
要在Jersey客户端中禁用SSL校验(仅用于测试环境,生产环境绝对禁止使用),需要自定义SSLContext和HostnameVerifier,具体实现如下:
- 创建信任所有证书的TrustManager,跳过证书合法性校验
- 创建跳过主机名匹配校验的HostnameVerifier
- 将自定义配置注入到Jersey Client的配置中
完整修改后的代码:
import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.SSLSession; import java.security.cert.X509Certificate; import java.security.NoSuchAlgorithmException; import java.security.KeyManagementException; // 保留原有导入类 public class YourServiceClass { // 原有类属性和方法 public void executePaymentRequest() { try { // 1. 定义信任所有证书的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) {} } }; // 2. 初始化自定义SSLContext SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(null, trustAllCerts, new java.security.SecureRandom()); // 3. 定义跳过主机名校验的HostnameVerifier HostnameVerifier skipHostnameVerify = new HostnameVerifier() { @Override public boolean verify(String hostname, SSLSession session) { return true; } }; // 4. 配置Jersey Client ClientConfig clientConfig = new ClientConfig(); clientConfig.register(JacksonFeature.class); // 注入自定义SSL上下文和主机名校验器 clientConfig.property("jersey.config.client.ssl.context", sslContext); clientConfig.property("jersey.config.client.hostname.verifier", skipHostnameVerify); Client client = ClientBuilder.newClient(clientConfig); // --- 以下为原有业务代码 --- WebTarget webTarget = client.target(rootUrl); Invocation.Builder invocationBuilder = webTarget.request(javax.ws.rs.core.MediaType.APPLICATION_JSON); MultivaluedMap<String, Object> header = new MultivaluedHashMap<>(); header.add("UserName", username); header.add("Password", password); invocationBuilder.headers(header); logger.info("Initialisation of cashout service successful"); Gson gson = new Gson(); String transactionString = gson.toJson(request); try { Response response = invocationBuilder.put(Entity.entity(transactionString, javax.ws.rs.core.MediaType.APPLICATION_JSON)); if(response.getStatus() == 200) { logger.info("The paiement is done, we got 200 code return"); responseData = response.readEntity(AirtimePaymentResponse.class); logger.info("the response data is {} ", responseData); }else { logger.info("error during the paiement"); throw new GGException("Error during the paiement", HttpStatus.valueOf(response.getStatus())); } }catch (Exception e) { throw new GGException(e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR); } } catch (NoSuchAlgorithmException | KeyManagementException e) { throw new GGException("Failed to configure SSL context", HttpStatus.INTERNAL_SERVER_ERROR); } } }
重要提示
- 禁用SSL校验会完全消除HTTPS的安全防护,存在中间人攻击风险,仅允许在本地测试或非生产环境临时使用。
- 生产环境的正确解决方式:
- 确认API域名的SSL证书包含正确的Subject Alternative Name(SAN)字段
- 将该证书导入到Java系统信任库(cacerts)中
内容的提问来源于stack exchange,提问作者Teddy Kossoko
相关产品推荐
相关产品推荐

