Loading

How to solve the problem of getting HostName Verification Exception in HTTP Requester

게시 일자: Mar 2, 2024
솔루션

SYMPTOM

When using HTTP Requester to establish HTTPS connection to remote server, if you are encountering the following exception
Error sending HTTP request. (org.mule.api.MessagingException)
  sun.security.util.HostnameChecker.matchDNS(HostnameChecker.java:204)
  sun.security.util.HostnameChecker.match(HostnameChecker.java:95)
  sun.security.ssl.X509TrustManagerImpl.checkIdentity(X509TrustManagerImpl.java:455)
  sun.security.ssl.X509TrustManagerImpl.checkIdentity(X509TrustManagerImpl.java:436)
  sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:252)
  sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:136)
  sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1501)
  sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:216)
  sun.security.ssl.Handshaker.processLoop(Handshaker.java:1026)
  sun.security.ssl.Handshaker$1.run(Handshaker.java:966)
  sun.security.ssl.Handshaker$1.run(Handshaker.java:963)
  java.security.AccessController.doPrivileged(AccessController.java:-2)
  sun.security.ssl.Handshaker$DelegatedTask.run(Handshaker.java:1416)
  org.glassfish.grizzly.ssl.SSLUtils.executeDelegatedTask(SSLUtils.java:274)
  org.glassfish.grizzly.ssl.SSLBaseFilter.doHandshakeStep(SSLBaseFilter.java:709)
  org.glassfish.grizzly.ssl.SSLFilter.doHandshakeStep(SSLFilter.java:332)
  org.glassfish.grizzly.ssl.SSLBaseFilter.doHandshakeStep(SSLBaseFilter.java:623)
  org.glassfish.grizzly.ssl.SSLBaseFilter.handleRead(SSLBaseFilter.java:328)
  com.ning.http.client.providers.grizzly.SwitchingSSLFilter.handleRead(SwitchingSSLFilter.java:74)
  org.glassfish.grizzly.filterchain.ExecutorResolver$9.execute(ExecutorResolver.java:119)
  org.glassfish.grizzly.filterchain.DefaultFilterChain.executeFilter(DefaultFilterChain.java:284)
  org.glassfish.grizzly.filterchain.DefaultFilterChain.executeChainPart(DefaultFilterChain.java:201)
  org.glassfish.grizzly.filterchain.DefaultFilterChain.execute(DefaultFilterChain.java:133)
  org.glassfish.grizzly.filterchain.DefaultFilterChain.process(DefaultFilterChain.java:112)
  org.glassfish.grizzly.ProcessorExecutor.execute(ProcessorExecutor.java:77)
  org.glassfish.grizzly.nio.transport.TCPNIOTransport.fireIOEvent(TCPNIOTransport.java:539)
  org.glassfish.grizzly.strategies.AbstractIOStrategy.fireIOEvent(AbstractIOStrategy.java:112)
  org.mule.module.http.internal.request.grizzly.FlowWorkManagerIOStrategy.run0(FlowWorkManagerIOStrategy.java:134)
  org.mule.module.http.internal.request.grizzly.FlowWorkManagerIOStrategy.access$100(FlowWorkManagerIOStrategy.java:31)
  org.mule.module.http.internal.request.grizzly.FlowWorkManagerIOStrategy$WorkerThreadRunnable.run(FlowWorkManagerIOStrategy.java:157)
  (3 more...)
It indicates that your application is not able to establish SSL connection to remote server, due to Hostname verification failure.

CAUSE

A host name verifier ensures the host name in the URL to which the client connects matches the host name in the digital certificate that the server sends back as part of the SSL connection. 

For example, if you are sending a HTTPS request to external server www.foo.com, the host name verification will perform the comparison between the following two values:
  1. the host value in the HTTP requester
  2. the DNSName value in the remote sever's certificate, you can obtain the DNSName value from the extension part of the certificate by calling the keytool list command (if you are using java key store)
    keytool -list -v -keystore <your keystore file>
    The DNSName value is in the "Extensions" section
  3. Extensions:
    
    #1: ObjectId: 2.5.29.17 Criticality=false
    SubjectAlternativeName [
      DNSName: foo.com
      IPAddress: 127.0.0.1
    ]
    
    #2: ObjectId: 2.5.29.14 Criticality=false
    SubjectKeyIdentifier [
    KeyIdentifier [
    0000: EE 38 10 6C BC A0 15 6F   35 C6 04 AF 90 2A E0 56  .8.l...o5....*.V
    0010: 6D 9A 2C F9                                        m.,.
    ]
    ]
In JSSE implementation, the comparison of the two values is performed in case-insensitive manner, which means foo.com and FoO.CoM are identical. Hostname verification in layer 7 validation logic, different protocol has different implementation. i.e., HTTPS and LDAPS will have different logic and requirement. This article is for HTTPS only.

SOLUTION

To meet the purpose of hostname verification, when obtaining the certificate from CA or generating the self-signed certificate, please ensure the "Extensions" section include the server's domain name. 
For self-signed certificate, you can generate the certificate using the following command if the server is deployed at foo.com:
keytool -genkey -alias server  -keyalg RSA -keystore <server key store file> -ext SAN="dns:foo.com,dns:blahblah.com,ip:127.0.0.1"
You can include multiple dnsname extensions.

ALTERNATIVE SOLUTION

If you remote server's certificate can not be changed, for example, if it only has DNSName "foo-A.com", you can try to ensure that your DNS server is able to resolve "foo-A.com" to your target server's IP address, and in your HTTP Requester, you configure it to send the request to "foo-A.com" instead.
 
Knowledge 기사 번호

001118465

 
로드 중
Salesforce Help | Article