【问题标题】:apache httpclient 4.4: HostnameVerifier transition from 4.3.xapache httpclient 4.4:HostnameVerifier 从 4.3.x 过渡
【发布时间】:2026-01-08 03:05:02
【问题描述】:

HttpClient 4.3 在org.apache.http.conn.ssl.SSLConnectionSocketFactory 中有三个静态变量:

  1. STRICT_HOSTNAME_VERIFIER
  2. BROWSER_COMPATIBLE_HOSTNAME_VERIFIER
  3. ALLOW_ALL__HOSTNAME_VERIFIER

在将依赖项升级到 HttpClient 的 4.4 版本时,我看到上述所有常量都已弃用。 JavaDoc 中的弃用说明提到使用org.apache.http.conn.ssl.DefaultHostnameVerifier。阅读文档,我假设DefaultHostnameVerifierSTRICT_HOSTNAME_VERIFIER 的直接替代品。 ALLOW_ALL__HOSTNAME_VERIFIER 也很容易实现:

package org.wiztools.restclient.http;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLSession;

/**
 *
 * @author subwiz
 */
public class AllowAllHostnameVerifier implements HostnameVerifier {

    @Override
    public boolean verify(String string, SSLSession ssls) {
        return true;
    }

}

STRICT_HOSTNAME_VERIFIERBROWSER_COMPATIBLE_HOSTNAME_VERIFIER 之间存在细微差别(来自 JavaDoc):

BROWSER_COMPATIBLE 和 STRICT 之间的唯一区别是带有 BROWSER_COMPATIBLE 的通配符(例如“*.foo.com”)匹配所有子域,包括“a.b.foo.com”。

我们是否有现成的用于 httpclient 4.4 的 BROWSER_COMPATIBLE 主机名验证器?

【问题讨论】:

    标签: java apache-httpclient-4.x


    【解决方案1】:

    其实AllowAllHostnameVerifier的javadoc直接替换了ALLOW_ALL__HOSTNAME_VERIFIER,也就是NoopHostnameVerifier

    【讨论】:

    • 我一直在寻找不推荐使用的方法来执行 ALLOW_ALL_HOSTNAME_VERIFIER 并且 NoopHostnameVerifier 有效。只需将函数的第二个参数替换为该类的实例即可:SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory( sslContext, new NoopHostnameVerifier());
    【解决方案2】:

    您不需要AllowAllHostnameVerifier 的新实现类,也不需要BrowserCompatHostnameVerifier 的另一个实现,只需将实例传递给新的DefaultHostnameVerifier

    SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new DefaultHostnameVerifier());
    

    这个类是具有以下方法签名的两者的必要验证方法

    public final boolean verify(String host, SSLSession session) (Override)
    

    public final void verify(String host, X509Certificate cert) throws SSLException
    

    在第二种方法中,httpcomponents 会检查匹配的子域

    public final void verify(String host, X509Certificate cert) throws SSLException {
        boolean ipv4 = InetAddressUtils.isIPv4Address(host);
        boolean ipv6 = InetAddressUtils.isIPv6Address(host);
        int subjectType = ((ipv4) || (ipv6)) ? 7 : 2;
        List subjectAlts = extractSubjectAlts(cert, subjectType);
        if ((subjectAlts != null) && (!(subjectAlts.isEmpty()))) {
            if (ipv4)
                matchIPAddress(host, subjectAlts);
            else if (ipv6)
                matchIPv6Address(host, subjectAlts);
            else {
                matchDNSName(host, subjectAlts, this.publicSuffixMatcher);
            }
        } else {
            X500Principal subjectPrincipal = cert.getSubjectX500Principal();
            String cn = extractCN(subjectPrincipal.getName("RFC2253"));
            if (cn == null) {
                throw new SSLException("Certificate subject for <" + host + "> doesn't contain " + "a common name and does not have alternative names");
            }
    
            matchCN(host, cn, this.publicSuffixMatcher);
        }
    }
    

    查看源代码以获得更多说明

    org.apache.http.conn.ssl.DefaultHostnameVerifier

    希望这会有所帮助。

    【讨论】:

      【解决方案3】:

      BrowserCompatHostnameVerifier 本质上是与 IE 5/6 兼容的实现。我不确定它是否真的与更现代的浏览器应用程序兼容。 BrowserCompatHostnameVerifier 本来就不应该存在,也不应该再被使用。

      【讨论】:

        【解决方案4】:

        我阅读了所有这些内容,但对我没有任何帮助,这就是拯救我的一天:https://*.com/a/36507502/3090309

        我正在使用:

        compile group: 'org.apache.httpcomponents', name: 'httpclient', version: '4.5.2'
        

        【讨论】: