java - 如何在spring webclient中禁用主机名验证?
问题描述
我正在使用 spring webflux webclient 工具来调用 API。API服务器地址是HTTPS,是一个没有域名的IP地址。我需要在 webclient 中禁用主机名验证。现在的异常如下
Caused by: java.security.cert.CertificateException: No subject alternative names matching IP address 180.101.147.89 found
at sun.security.util.HostnameChecker.matchIP(HostnameChecker.java:168) ~[na:1.8.0_211]
at sun.security.util.HostnameChecker.match(HostnameChecker.java:94) ~[na:1.8.0_211]
at sun.security.ssl.X509TrustManagerImpl.checkIdentity(X509TrustManagerImpl.java:461) ~[na:1.8.0_211]
at sun.security.ssl.X509TrustManagerImpl.checkIdentity(X509TrustManagerImpl.java:442) ~[na:1.8.0_211]
at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:260) ~[na:1.8.0_211]
at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:144) ~[na:1.8.0_211]
at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1626) ~[na:1.8.0_211]
... 28 common frames omitted
@Bean
public WebClient telcomWebclient(WebClient.Builder webClientBuilder,
@Value("${telcom.api.host}") String telcomApiHost,
@Value("${telcom.api.certificate-name}") String telcomApiCertificateName,
@Value("${telcom.api.certificate-store-pass}") String telcomApiCertificateStorePass) {
try {
KeyStore selfCert = KeyStore.getInstance("pkcs12");
selfCert.load(getClass().getResourceAsStream("/cert/outgoing.CertwithKey.pkcs12"), "IoM@1234".toCharArray());
KeyManagerFactory kmf = KeyManagerFactory.getInstance("sunx509");
kmf.init(selfCert, "IoM@1234".toCharArray());
KeyStore caCert = KeyStore.getInstance("jks");
caCert.load(getClass().getResourceAsStream("/cert/" + telcomApiCertificateName), telcomApiCertificateStorePass.toCharArray());
TrustManagerFactory tmf = TrustManagerFactory.getInstance("sunx509");
tmf.init(caCert);
SslContext sslContext = SslContextBuilder.forClient()
.keyManager(kmf)
.trustManager(tmf)
.build();
HttpClient httpClient = HttpClient.create().create().secure(sslContextSpec -> sslContextSpec.sslContext(sslContext));
ClientHttpConnector clientHttpConnector = new ReactorClientHttpConnector(httpClient);
return webClientBuilder.clientConnector(clientHttpConnector).baseUrl(telcomApiHost).build();
} catch (KeyStoreException | IOException | NoSuchAlgorithmException | CertificateException | UnrecoverableKeyException e) {
log.error("Config webclient,error occurs", e);
System.exit(-1);
}
return null;
}
解决方案
除了完全禁用 SSL 验证之外,(我不推荐)通过InsecureTrustManagerFactory.INSTANCE
像这样传入:
SslContext sslContext = SslContextBuilder.forClient()
.keyManager(kmf)
.trustManager(InsecureTrustManagerFactory.INSTANCE)
.build();
您可以通过配置自定义SNIMatcher来将 HttpClient 配置为基本上覆盖主机名验证,如下所示:
HttpClient.create().create().secure(sslContextSpec -> sslContextSpec
.sslContext(sslContext)
.handlerConfigurator(sslHandler ->
SSLEngine engine = handler.engine();
//engine.setNeedClientAuth(true);
SSLParameters params = new SSLParameters();
List<SNIMatcher> matchers = new LinkedList<>();
SNIMatcher matcher = new SNIMatcher(0) {
@Override
public boolean matches(SNIServerName serverName) {
return true;
}
};
matchers.add(matcher);
params.setSNIMatchers(matchers);
engine.setSSLParameters(params);
);
我已经对此进行了测试并验证了它是否有效。我希望这有帮助!
这受到此处答案的启发:Configure HostnameVerifier with reactor netty for spring-webflux WebClient
推荐阅读
- loopbackjs - 用于动态路由的路由装饰器,允许将斜杠作为变量字符串的一部分
- arm - 加载/存储单元和管道中
- javascript - 当用户在谷歌浏览器中按下后退按钮时,如何加载最后一个状态?
- oracle - oracle ebs 表单中的特殊值设置错误
- javascript - MVC:如何将 .js 文件的内容呈现到脚本标签中
- javascript - 如何通过从 PHP 获取值来使用 javascript 动态播放音频?
- python - 使用整数而不是浮点数进行矩阵运算
- java - 自 Spring 5.0 以来引入的关于 RFC1123 的可能错误;ANSI C 的 asctime
- robotframework - Robot Framework 中的任务和测试用例有什么区别?
- laravel - 重定向“此路由不支持方法”