【问题标题】:Trusting all certificates using HttpClient over HTTPS通过 HTTPS 使用 HttpClient 信任所有证书
【发布时间】:2011-02-08 05:22:51
【问题描述】:

最近发布了一个关于HttpClient over Https (found here) 的问题。我已经取得了一些进展,但我遇到了新问题。与我的上一个问题一样,我似乎无法在任何地方找到适合我的示例。基本上,我希望我的客户接受任何证书(因为我只指向一台服务器)但我不断收到javax.net.ssl.SSLException: Not trusted server certificate exception.

这就是我所拥有的:


    public void connect() throws A_WHOLE_BUNCH_OF_EXCEPTIONS {

        HttpPost post = new HttpPost(new URI(PROD_URL));
        post.setEntity(new StringEntity(BODY));

        KeyStore trusted = KeyStore.getInstance("BKS");
        trusted.load(null, "".toCharArray());
        SSLSocketFactory sslf = new SSLSocketFactory(trusted);
        sslf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);

        SchemeRegistry schemeRegistry = new SchemeRegistry();
        schemeRegistry.register(new Scheme ("https", sslf, 443));
        SingleClientConnManager cm = new SingleClientConnManager(post.getParams(),
                schemeRegistry);

        HttpClient client = new DefaultHttpClient(cm, post.getParams());
        HttpResponse result = client.execute(post);
    }

这是我得到的错误:

    W/System.err(  901): javax.net.ssl.SSLException: Not trusted server certificate 
    W/System.err(  901):    at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:360) 
    W/System.err(  901):    at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:92) 
    W/System.err(  901):    at org.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java:321) 
    W/System.err(  901):    at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:129) 
    W/System.err(  901):    at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:164) 
    W/System.err(  901):    at org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:119) 
    W/System.err(  901):    at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:348) 
    W/System.err(  901):    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:555) 
    W/System.err(  901):    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:487) 
    W/System.err(  901):    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:465) 
    W/System.err(  901):    at me.harrisonlee.test.ssl.MainActivity.connect(MainActivity.java:129) 
    W/System.err(  901):    at me.harrisonlee.test.ssl.MainActivity.access$0(MainActivity.java:77) 
    W/System.err(  901):    at me.harrisonlee.test.ssl.MainActivity$2.run(MainActivity.java:49) 
    W/System.err(  901): Caused by: java.security.cert.CertificateException: java.security.InvalidAlgorithmParameterException: the trust anchors set is empty 
    W/System.err(  901):    at org.apache.harmony.xnet.provider.jsse.TrustManagerImpl.checkServerTrusted(TrustManagerImpl.java:157) 
    W/System.err(  901):    at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:355) 
    W/System.err(  901):    ... 12 more 
    W/System.err(  901): Caused by: java.security.InvalidAlgorithmParameterException: the trust anchors set is empty 
    W/System.err(  901):    at java.security.cert.PKIXParameters.checkTrustAnchors(PKIXParameters.java:645) 
    W/System.err(  901):    at java.security.cert.PKIXParameters.<init>(PKIXParameters.java:89) 
    W/System.err(  901):    at org.apache.harmony.xnet.provider.jsse.TrustManagerImpl.<init>(TrustManagerImpl.java:89) 
    W/System.err(  901):    at org.apache.harmony.xnet.provider.jsse.TrustManagerFactoryImpl.engineGetTrustManagers(TrustManagerFactoryImpl.java:134) 
    W/System.err(  901):    at javax.net.ssl.TrustManagerFactory.getTrustManagers(TrustManagerFactory.java:226)W/System.err(  901):     at org.apache.http.conn.ssl.SSLSocketFactory.createTrustManagers(SSLSocketFactory.java:263) 
    W/System.err(  901):    at org.apache.http.conn.ssl.SSLSocketFactory.<init>(SSLSocketFactory.java:190) 
    W/System.err(  901):    at org.apache.http.conn.ssl.SSLSocketFactory.<init>(SSLSocketFactory.java:216) 
    W/System.err(  901):    at me.harrisonlee.test.ssl.MainActivity.connect(MainActivity.java:107) 
    W/System.err(  901):    ... 2 more

【问题讨论】:

  • 我需要这样做以供内部使用。我真的希望您不要让公司以外的用户使用您的应用程序,因为您已将其开放给中间人攻击,然后他们将很容易受到有人劫持他们的会话的攻击。尽管如此,我需要临时做一些测试,直到我拿到真正的证书......希望你这样做是出于同样的临时原因,或者该应用程序仅在内部使用。
  • 我在 4.3 apache http 客户端上尝试了这些解决方案,但它们大多已被弃用。这是不推荐使用的解决方案:stackoverflow.com/a/18941950/2039471
  • Java 1.6 没有 SNI 支持,这在这些情况下也存在问题 - 如果您没有正确构造请求,您可能会获得与请求不匹配的证书。见issues.apache.org/jira/browse/HTTPCLIENT-1119
  • 世界上最危险的代码一文中引用了这个问题作为错误推理的一个例子。 (研究论文:cs.utexas.edu/~shmat/shmat_ccs12.pdf

标签: java ssl https certificate apache-httpclient-4.x


【解决方案1】:

您基本上有四种潜在的解决方案来使用 httpclient 修复 Android 上的“不可信”异常:

  1. 信任所有证书。不要这样做,除非你真的知道自己在做什么。
  2. 创建一个只信任您的证书的自定义 SSLSocketFactory。只要您确切知道要连接到哪些服务器,此方法就可以使用,但是一旦您需要使用不同的 SSL 证书连接到新服务器,您就需要更新您的应用。
  3. 创建一个包含 Android 证书“主列表”的密钥库文件,然后添加您自己的。如果这些证书中的任何一个过期,您有责任在您的应​​用程序中更新它们。我想不出这样做的理由。
  4. 创建一个使用内置证书 KeyStore 的自定义 SSLSocketFactory,但如果使用默认值验证失败,则使用备用 KeyStore。

此答案使用解决方案 #4,在我看来这是最可靠的。

解决方案是使用可以接受多个 KeyStore 的 SSLSocketFactory,允许您使用自己的证书提供自己的 KeyStore。这允许您加载其他顶级证书,例如某些 Android 设备上可能缺少的 Thawte。它还允许您加载自己的自签名证书。它将首先使用内置的默认设备证书,并仅在必要时使用您的其他证书。

首先,您需要确定您的 KeyStore 中缺少哪个证书。运行以下命令:

openssl s_client -connect www.yourserver.com:443

你会看到如下输出:

Certificate chain
 0 s:/O=www.yourserver.com/OU=Go to 
   https://www.thawte.com/repository/index.html/OU=Thawte SSL123 
   certificate/OU=Domain Validated/CN=www.yourserver.com
   i:/C=US/O=Thawte, Inc./OU=Domain Validated SSL/CN=Thawte DV SSL CA
 1 s:/C=US/O=Thawte, Inc./OU=Domain Validated SSL/CN=Thawte DV SSL CA
   i:/C=US/O=thawte, Inc./OU=Certification Services Division/OU=(c) 
   2006 thawte, Inc. - For authorized use only/CN=thawte Primary Root CA

如您所见,我们的根证书来自 Thawte。访问您的提供商的网站并找到相应的证书。对我们来说,它是 here,您可以看到我们需要的是版权 2006。

如果您使用的是自签名证书,则无需执行上一步,因为您已经拥有签名证书。

然后,创建一个包含缺少的签名证书的密钥库文件。 Crazybob 有details how to do this on Android,但想法是执行以下操作:

如果您还没有,请从以下位置下载充气城堡提供程序库:http://www.bouncycastle.org/latest_releases.html。这将在下面的类路径中进行。

运行命令从服务器提取证书并创建 pem 文件。在这种情况下,mycert.pem。

echo | openssl s_client -connect ${MY_SERVER}:443 2>&1 | \
 sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > mycert.pem

然后运行以下命令来创建密钥库。

export CLASSPATH=/path/to/bouncycastle/bcprov-jdk15on-155.jar
CERTSTORE=res/raw/mystore.bks
if [ -a $CERTSTORE ]; then
    rm $CERTSTORE || exit 1
fi
keytool \
      -import \
      -v \
      -trustcacerts \
      -alias 0 \
      -file <(openssl x509 -in mycert.pem) \
      -keystore $CERTSTORE \
      -storetype BKS \
      -provider org.bouncycastle.jce.provider.BouncyCastleProvider \
      -providerpath /path/to/bouncycastle/bcprov-jdk15on-155.jar \
      -storepass some-password

您会注意到上面的脚本将结果放在res/raw/mystore.bks 中。现在您有一个文件,您将加载到您的 Android 应用程序中,该文件提供缺少的证书。

为此,请为 SSL 方案注册您的 SSLSocketFactory:

final SchemeRegistry schemeRegistry = new SchemeRegistry();
schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
schemeRegistry.register(new Scheme("https", createAdditionalCertsSSLSocketFactory(), 443));

// and then however you create your connection manager, I use ThreadSafeClientConnManager
final HttpParams params = new BasicHttpParams();
...
final ThreadSafeClientConnManager cm = new ThreadSafeClientConnManager(params,schemeRegistry);

创建你的 SSLSocketFactory:

protected org.apache.http.conn.ssl.SSLSocketFactory createAdditionalCertsSSLSocketFactory() {
    try {
        final KeyStore ks = KeyStore.getInstance("BKS");

        // the bks file we generated above
        final InputStream in = context.getResources().openRawResource( R.raw.mystore);  
        try {
            // don't forget to put the password used above in strings.xml/mystore_password
            ks.load(in, context.getString( R.string.mystore_password ).toCharArray());
        } finally {
            in.close();
        }

        return new AdditionalKeyStoresSSLSocketFactory(ks);

    } catch( Exception e ) {
        throw new RuntimeException(e);
    }
}

最后是 AdditionalKeyStoresSSLSocketFactory 代码,它接受您的新 KeyStore 并检查内置 KeyStore 是否无法验证 SSL 证书:

/**
 * Allows you to trust certificates from additional KeyStores in addition to
 * the default KeyStore
 */
public class AdditionalKeyStoresSSLSocketFactory extends SSLSocketFactory {
    protected SSLContext sslContext = SSLContext.getInstance("TLS");

    public AdditionalKeyStoresSSLSocketFactory(KeyStore keyStore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
        super(null, null, null, null, null, null);
        sslContext.init(null, new TrustManager[]{new AdditionalKeyStoresTrustManager(keyStore)}, null);
    }

    @Override
    public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException {
        return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose);
    }

    @Override
    public Socket createSocket() throws IOException {
        return sslContext.getSocketFactory().createSocket();
    }



    /**
     * Based on http://download.oracle.com/javase/1.5.0/docs/guide/security/jsse/JSSERefGuide.html#X509TrustManager
     */
    public static class AdditionalKeyStoresTrustManager implements X509TrustManager {

        protected ArrayList<X509TrustManager> x509TrustManagers = new ArrayList<X509TrustManager>();


        protected AdditionalKeyStoresTrustManager(KeyStore... additionalkeyStores) {
            final ArrayList<TrustManagerFactory> factories = new ArrayList<TrustManagerFactory>();

            try {
                // The default Trustmanager with default keystore
                final TrustManagerFactory original = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
                original.init((KeyStore) null);
                factories.add(original);

                for( KeyStore keyStore : additionalkeyStores ) {
                    final TrustManagerFactory additionalCerts = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
                    additionalCerts.init(keyStore);
                    factories.add(additionalCerts);
                }

            } catch (Exception e) {
                throw new RuntimeException(e);
            }



            /*
             * Iterate over the returned trustmanagers, and hold on
             * to any that are X509TrustManagers
             */
            for (TrustManagerFactory tmf : factories)
                for( TrustManager tm : tmf.getTrustManagers() )
                    if (tm instanceof X509TrustManager)
                        x509TrustManagers.add( (X509TrustManager)tm );


            if( x509TrustManagers.size()==0 )
                throw new RuntimeException("Couldn't find any X509TrustManagers");

        }

        /*
         * Delegate to the default trust manager.
         */
        public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
            final X509TrustManager defaultX509TrustManager = x509TrustManagers.get(0);
            defaultX509TrustManager.checkClientTrusted(chain, authType);
        }

        /*
         * Loop over the trustmanagers until we find one that accepts our server
         */
        public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
            for( X509TrustManager tm : x509TrustManagers ) {
                try {
                    tm.checkServerTrusted(chain,authType);
                    return;
                } catch( CertificateException e ) {
                    // ignore
                }
            }
            throw new CertificateException();
        }

        public X509Certificate[] getAcceptedIssuers() {
            final ArrayList<X509Certificate> list = new ArrayList<X509Certificate>();
            for( X509TrustManager tm : x509TrustManagers )
                list.addAll(Arrays.asList(tm.getAcceptedIssuers()));
            return list.toArray(new X509Certificate[list.size()]);
        }
    }

}

【讨论】:

  • 嘿@emmby,这似乎是解决我的问题的完美答案,但我仍然没有 SSL 连接。你能看一下吗? http://stackoverflow.com/questions/7822381/need-help-understanding-certificate-chains
  • 感谢@emmby 的精彩文章!我有时会遇到很长的延迟,然后是 javax.net.ssl.SSLException: Read error:.任何想法?如果解决方案与stackoverflow.com/questions/5909308/android-2-3-4-ssl-problem相同,如何设置超时?
  • @emmby,你能告诉我应该把这段代码放在哪里吗 export CLASSPATH=bcprov-jdk16-145.jar CERTSTORE=res/raw/mystore.bks if [ -a $CERTSTORE ];然后 rm $CERTSTORE ||退出 1 fi keytool \ -import \ -v \ -trustcacerts \ -alias 0 \ -file
  • 嘿@emmby。我在我的应用程序中使用您的解决方案并使用我的服务器的自签名证书,但在 checkServerTrusted() 方法中获得了一个 CertificateException()。我尝试评论该抛出异常,并且它有效。如果它没有验证我的服务器证书,那么我可以用其他方式处理它吗,你能指导一下在这种情况下什么是最好的解决方案吗?
  • 这应该被标记为正确答案。我在 SO 上见过的最彻底和写得最好的答案之一。涂料
【解决方案2】:

注意:不要在您不完全信任的网络上使用的生产代码中实现此功能。尤其是通过公共互联网传播的任何内容。

你的问题正是我想知道的。经过一番搜索,结论如下。

在 HttpClient 方式中,您应该从 org.apache.http.conn.ssl.SSLSocketFactory 创建一个自定义类,而不是一个 org.apache.http.conn.ssl.SSLSocketFactory 本身。一些线索可以在这篇帖子Custom SSL handling stopped working on Android 2.2 FroYo中找到。

举个例子……

import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import org.apache.http.conn.ssl.SSLSocketFactory;
public class MySSLSocketFactory extends SSLSocketFactory {
    SSLContext sslContext = SSLContext.getInstance("TLS");

    public MySSLSocketFactory(KeyStore truststore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
        super(truststore);

        TrustManager tm = new X509TrustManager() {
            public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
            }

            public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
            }

            public X509Certificate[] getAcceptedIssuers() {
                return null;
            }
        };

        sslContext.init(null, new TrustManager[] { tm }, null);
    }

    @Override
    public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException, UnknownHostException {
        return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose);
    }

    @Override
    public Socket createSocket() throws IOException {
        return sslContext.getSocketFactory().createSocket();
    }
}

并在创建 HttpClient 实例时使用此类。

public HttpClient getNewHttpClient() {
    try {
        KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
        trustStore.load(null, null);

        MySSLSocketFactory sf = new MySSLSocketFactory(trustStore);
        sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);

        HttpParams params = new BasicHttpParams();
        HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
        HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);

        SchemeRegistry registry = new SchemeRegistry();
        registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
        registry.register(new Scheme("https", sf, 443));

        ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry);

        return new DefaultHttpClient(ccm, params);
    } catch (Exception e) {
        return new DefaultHttpClient();
    }
}

顺便说一句,下面的链接适用于正在寻找 HttpURLConnection 解决方案的人。 Https Connection Android

我已经在 froyo 上测试了上述两种解决方案,它们在我的案例中都非常有效。最后,使用 HttpURLConnection 可能会面临重定向问题,但这超出了主题。

注意:在您决定信任所有证书之前,您可能应该充分了解该站点并且不会对最终用户造成危害。

确实,应该仔细考虑您所承担的风险,包括我非常感谢的以下 cmets 中提到的黑客模拟站点的影响。在某些情况下,虽然可能很难处理所有证书,但您最好了解信任所有证书的隐含缺点。

【讨论】:

  • 这个答案可能应该指出,信任所有证书是非常不安全的,并且会使 ssl 的全部目的无效......
  • @sweeney - 除了不能保证您正在与您认为的服务器交谈。如果有人破坏了 DNS 服务器,您可能正在与黑客的服务器通信加密密钥。
  • @sweeney 换句话说,您现在很容易受到中间人攻击。您还应该注意该代码不符合规范:检查 Javadoc。 getAcceptedIssuers() 不允许返回 null。
  • -1 因为接受所有证书是一个糟糕的主意。太糟糕了,有这么多博客和教程可以愉快地引导 Java 开发人员走上错误的道路。
  • +1 因为我需要一个仅用于调试目的的快速解决方案。由于其他人提到的安全问题,我不会在生产中使用它,但这正是我测试所需要的。谢谢!
【解决方案3】:

HttpsURLConnection 之前添加此代码即可完成。我明白了。

private void trustEveryone() { 
    try { 
            HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier(){ 
                    public boolean verify(String hostname, SSLSession session) { 
                            return true; 
                    }}); 
            SSLContext context = SSLContext.getInstance("TLS"); 
            context.init(null, new X509TrustManager[]{new X509TrustManager(){ 
                    public void checkClientTrusted(X509Certificate[] chain, 
                                    String authType) throws CertificateException {} 
                    public void checkServerTrusted(X509Certificate[] chain, 
                                    String authType) throws CertificateException {} 
                    public X509Certificate[] getAcceptedIssuers() { 
                            return new X509Certificate[0]; 
                    }}}, new SecureRandom()); 
            HttpsURLConnection.setDefaultSSLSocketFactory( 
                            context.getSocketFactory()); 
    } catch (Exception e) { // should never happen 
            e.printStackTrace(); 
    } 
} 

希望对你有帮助。

【讨论】:

  • 这是理想的问答解决方案。简短且“有效”。
  • 测试的完美答案!!!是的,在生产中使用它是一个坏主意,但是来吧……每个查看问题标题的人都应该清楚这一点。它仍然回答最好/最短/具有相同的(in)安全级别!
  • 添加后这是应用程序授予 Playstore 上传权限?
【解决方案4】:

这是个坏主意。信任任何证书只(非常)比完全不使用 SSL 稍微好一点。当您说“我希望我的客户接受任何证书(因为我只指向一台服务器)”时,您假设这意味着以某种方式指向“一台服务器”是安全的,它不在公共网络上。

通过信任任何证书,您完全容易受到中间人攻击。任何人都可以通过与您和终端服务器建立单独的 SSL 连接来代理您的连接。然后,MITM 可以访问您的整个请求和响应。除非您一开始并不真的需要 SSL(您的消息没有任何敏感信息,并且不进行身份验证),否则您不应该盲目地信任所有证书。

您应该考虑使用 keytool 将公共证书添加到 jks,并使用它来构建您的套接字工厂,例如:

    KeyStore ks = KeyStore.getInstance("JKS");

    // get user password and file input stream
    char[] password = ("mykspassword")).toCharArray();
    ClassLoader cl = this.getClass().getClassLoader();
    InputStream stream = cl.getResourceAsStream("myjks.jks");
    ks.load(stream, password);
    stream.close();

    SSLContext sc = SSLContext.getInstance("TLS");
    KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
    TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");

    kmf.init(ks, password);
    tmf.init(ks);

    sc.init(kmf.getKeyManagers(), tmf.getTrustManagers(),null);

    return sc.getSocketFactory();

这有一个需要注意的警告。证书最终会过期,届时代码将停止工作。您可以通过查看证书轻松确定何时会发生这种情况。

【讨论】:

  • 如果您不使用客户端证书身份验证,则从客户端,您不需要密钥管理器(在 SSLContext.init). You should also use the default algorithms (KMF/TMF.getDefaultAlgorithm() ), instead of hard-coding SunX509 中使用 null `(更多因为 TMF 的默认设置)实际上是 PKIX 在 Sun/Oracle JVM 上)。
  • 是否存在可以使用的根证书文件? (就像浏览器一样)
  • myjks.jks 是从哪里来的?
  • @zionpi 使用 Java“keytool”生成。
  • 如何从windows运行“export”命令,我下载bouncycastly jar文件,需要安装到windows吗?
【解决方案5】:

从 API 8 开始,您可以通过这种方式禁用 HttpURLConnection SSL 检查以进行测试:

    HttpURLConnection conn = (HttpURLConnection) url.openConnection();
    if (conn instanceof HttpsURLConnection) {
        HttpsURLConnection httpsConn = (HttpsURLConnection) conn;
        httpsConn.setSSLSocketFactory(SSLCertificateSocketFactory.getInsecure(0, null));
        httpsConn.setHostnameVerifier(new AllowAllHostnameVerifier());
    }

【讨论】:

  • org.apache.http.conn.ssl.AllowAllHostnameVerifier 已弃用。
  • @zackygaurav 根据javadocAllowAllHostnameVerifierNoopHostnameVerifier替换了"
【解决方案6】:

https://stackoverflow.com/a/6378872/1553004 中的上述代码是正确的,除了它还必须调用主机名验证器:

    @Override
public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException {
    SSLSocket sslSocket = (SSLSocket)sslContext.getSocketFactory().createSocket(socket, host, port, autoClose);
    getHostnameVerifier().verify(host, sslSocket);
    return sslSocket;
}

我特地注册了 stackoverflow 以添加此修复程序。注意我的警告!

【讨论】:

  • 在第一次连接时以这种方式验证证书后,您如何处理后续连接?您是否利用了从第一次连接中获得的知识?如果在连接尝试 3 上使用了同名的假证书怎么办?
【解决方案7】:

HttpComponents 的 API 已更改。它适用于下面的代码。

public static HttpClient getTestHttpClient() {
    try {
        SSLSocketFactory sf = new SSLSocketFactory(new TrustStrategy(){
            @Override
            public boolean isTrusted(X509Certificate[] chain,
                    String authType) throws CertificateException {
                return true;
            }
        }, new AllowAllHostnameVerifier());

        SchemeRegistry registry = new SchemeRegistry();
        registry.register(new Scheme("https",8444, sf));
        ClientConnectionManager ccm = new ThreadSafeClientConnManager(registry);
        return new DefaultHttpClient(ccm);
    } catch (Exception e) {
        e.printStackTrace();
        return new DefaultHttpClient();
    }
}

【讨论】:

  • 使用自定义信任策略是正确的答案。谢谢。
【解决方案8】:

我正在为使用 httpclient-4.5 的用户添加响应,并且可能也适用于 4.4。

import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.HttpResponseException;
import org.apache.http.client.fluent.ContentResponseHandler;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContextBuilder;



public class HttpClientUtils{

public static HttpClient getHttpClientWithoutSslValidation_UsingHttpClient_4_5_2() {
    try {
        SSLContextBuilder builder = new SSLContextBuilder();
        builder.loadTrustMaterial(null, new TrustStrategy() {
            @Override
            public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                return true;
            }
        });
        SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(builder.build(), new NoopHostnameVerifier());
        CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build(); 
        return httpclient;
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}
}

【讨论】:

  • 什么是新的 NoopH​​ostnameVerifier() 类?
  • @MushtakimAhmedAnsari 来自文档:“NO_OP HostnameVerifier 实质上关闭了主机名验证。此实现是无操作的,从不抛出 SSLException。”
  • 感谢您的出色回答。这个应该得到更多的支持。
  • 如何使用它?或者您是否建议仅使用该课程将覆盖 ssl 证书验证?
  • 是的。使用时 httpClient 不会验证 https 证书
【解决方案9】:

信任所有证书对我来说不是真正的选择,因此我执行以下操作以使 HttpsURLConnection 信任新证书(另请参阅 http://nelenkov.blogspot.jp/2011/12/using-custom-certificate-trust-store-on.html)。

  1. 获取证书;我通过在 Firefox 中导出证书来完成此操作(单击小锁图标,获取证书详细信息,单击导出),然后使用 portecle 导出信任库 (BKS)。

  2. 使用以下代码从 /res/raw/geotrust_cert.bks 加载信任库:

        final KeyStore trustStore = KeyStore.getInstance("BKS");
        final InputStream in = context.getResources().openRawResource(
                R.raw.geotrust_cert);
        trustStore.load(in, null);
    
        final TrustManagerFactory tmf = TrustManagerFactory
                .getInstance(TrustManagerFactory.getDefaultAlgorithm());
        tmf.init(trustStore);
    
        final SSLContext sslCtx = SSLContext.getInstance("TLS");
        sslCtx.init(null, tmf.getTrustManagers(),
                new java.security.SecureRandom());
    
        HttpsURLConnection.setDefaultSSLSocketFactory(sslCtx
                .getSocketFactory());
    

【讨论】:

  • 我收到此错误。 IOExceptionjavax.net.ssl.SSLPeerUnverifiedException: No peer certificate。这是在上述设置完成后对 HttpClient 进行实际执行调用时。
【解决方案10】:

这是一个使用 4.1.2 httpclient 代码的非常简单的版本。然后可以将其修改为您认为合适的任何信任算法。

public static HttpClient getTestHttpClient() {
    try {
        SSLSocketFactory sf = new SSLSocketFactory(new TrustStrategy(){
            @Override
            public boolean isTrusted(X509Certificate[] chain,
                    String authType) throws CertificateException {
                return true;
            }
        });
        SchemeRegistry registry = new SchemeRegistry();
        registry.register(new Scheme("https", 443, sf));
        ClientConnectionManager ccm = new ThreadSafeClientConnManager(registry);
        return new DefaultHttpClient(ccm);
    } catch (Exception e) {
        return new DefaultHttpClient();
    }
}

【讨论】:

    【解决方案11】:

    我看到了来自“emmby”的回复(2011 年 6 月 16 日 21:29 回答),第 4 项:“创建一个使用内置证书 KeyStore 的自定义 SSLSocketFactory,但使用备用 KeyStore任何无法使用默认值验证的内容。”

    这是一个简化的实现。加载系统密钥库并与应用程序密钥库合并。

    public HttpClient getNewHttpClient() {
        try {
            InputStream in = null;
            // Load default system keystore
            KeyStore trusted = KeyStore.getInstance(KeyStore.getDefaultType()); 
            try {
                in = new BufferedInputStream(new FileInputStream(System.getProperty("javax.net.ssl.trustStore"))); // Normally: "/system/etc/security/cacerts.bks"
                trusted.load(in, null); // no password is "changeit"
            } finally {
                if (in != null) {
                    in.close();
                    in = null;
                }
            }
    
            // Load application keystore & merge with system
            try {
                KeyStore appTrusted = KeyStore.getInstance("BKS"); 
                in = context.getResources().openRawResource(R.raw.mykeystore);
                appTrusted.load(in, null); // no password is "changeit"
                for (Enumeration<String> e = appTrusted.aliases(); e.hasMoreElements();) {
                    final String alias = e.nextElement();
                    final KeyStore.Entry entry = appTrusted.getEntry(alias, null);
                    trusted.setEntry(System.currentTimeMillis() + ":" + alias, entry, null);
                }
            } finally {
                if (in != null) {
                    in.close();
                    in = null;
                }
            }
    
            HttpParams params = new BasicHttpParams();
            HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
            HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);
    
            SSLSocketFactory sf = new SSLSocketFactory(trusted);
            sf.setHostnameVerifier(SSLSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
    
            SchemeRegistry registry = new SchemeRegistry();
            registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
            registry.register(new Scheme("https", sf, 443));
    
            ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry);
    
            return new DefaultHttpClient(ccm, params);
        } catch (Exception e) {
            return new DefaultHttpClient();
        }
    }
    

    从JKS转换为BKS的简单模式:

    keytool -importkeystore -destkeystore cacerts.bks -deststoretype BKS -providerclass org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath bcprov-jdk16-141.jar -deststorepass changeit -srcstorepass changeit -srckeystore $JAVA_HOME/jre/lib/security/cacerts -srcstoretype JKS -noprompt
    

    *注意:在 Android 4.0 (ICS) 中,Trust Store 已更改,更多信息:http://nelenkov.blogspot.com.es/2011/12/ics-trust-store-implementation.html

    【讨论】:

      【解决方案12】:

      对于那些希望允许所有证书通过 OAuth 工作(用于测试目的)的人,请按照以下步骤操作:

      1) 在此处下载 Android OAuth API 的源代码:https://github.com/kaeppler/signpost

      2) 找到文件“CommonsHttpOAuthProvider”类

      3) 如下修改:

      public class CommonsHttpOAuthProvider extends AbstractOAuthProvider {
      
      private static final long serialVersionUID = 1L;
      
      private transient HttpClient httpClient;
      
      public CommonsHttpOAuthProvider(String requestTokenEndpointUrl, String accessTokenEndpointUrl,
              String authorizationWebsiteUrl) {
          super(requestTokenEndpointUrl, accessTokenEndpointUrl, authorizationWebsiteUrl);
      
      
          //this.httpClient = new DefaultHttpClient();//Version implemented and that throws the famous "javax.net.ssl.SSLException: Not trusted server certificate" if the certificate is not signed with a CA
          this.httpClient = MySSLSocketFactory.getNewHttpClient();//This will work with all certificates (for testing purposes only)
      }
      

      上面的“MySSLSocketFactory”基于接受的答案。为了使它更容易,这里是完整的类:

      package com.netcomps.oauth_example;
      
      import java.io.IOException;
      import java.net.Socket;
      import java.net.UnknownHostException;
      import java.security.KeyManagementException;
      import java.security.KeyStore;
      import java.security.KeyStoreException;
      import java.security.NoSuchAlgorithmException;
      import java.security.UnrecoverableKeyException;
      import java.security.cert.CertificateException;
      import java.security.cert.X509Certificate;
      
      import javax.net.ssl.SSLContext;
      import javax.net.ssl.TrustManager;
      import javax.net.ssl.X509TrustManager;
      
      import org.apache.http.HttpVersion;
      import org.apache.http.client.HttpClient;
      import org.apache.http.conn.ClientConnectionManager;
      import org.apache.http.conn.scheme.PlainSocketFactory;
      import org.apache.http.conn.scheme.Scheme;
      import org.apache.http.conn.scheme.SchemeRegistry;
      import org.apache.http.conn.ssl.SSLSocketFactory;
      import org.apache.http.impl.client.DefaultHttpClient;
      import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
      import org.apache.http.params.BasicHttpParams;
      import org.apache.http.params.HttpParams;
      import org.apache.http.params.HttpProtocolParams;
      import org.apache.http.protocol.HTTP;
      
      //http://stackoverflow.com/questions/2642777/trusting-all-certificates-using-httpclient-over-https
      public class MySSLSocketFactory extends SSLSocketFactory {
      
          SSLContext sslContext = SSLContext.getInstance("TLS");
      
      public MySSLSocketFactory(KeyStore truststore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
      
          super(truststore);
          TrustManager tm = new X509TrustManager() {
      
              @Override
              public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
              }
      
              @Override
              public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
              }
      
              @Override
              public X509Certificate[] getAcceptedIssuers() {
                  return null;
              }
          };
      
          sslContext.init(null, new TrustManager[] { tm }, null);
      }
      
      @Override
      public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException, UnknownHostException {
          return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose);
      }
      
      @Override
      public Socket createSocket() throws IOException {
          return sslContext.getSocketFactory().createSocket();
      }
      
      
      
      public static HttpClient getNewHttpClient() {
      
          try {
              KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
              trustStore.load(null, null);
      
              SSLSocketFactory sf = new MySSLSocketFactory(trustStore);
              sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
      
              HttpParams params = new BasicHttpParams();
              HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
              HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);
      
              SchemeRegistry registry = new SchemeRegistry();
              registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
              registry.register(new Scheme("https", sf, 443));
      
              ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry);
      
              return new DefaultHttpClient(ccm, params);
      
          } catch (Exception e) {
              return new DefaultHttpClient();
          }
      }
      

      }

      希望这对某人有所帮助。

      【讨论】:

      • 问题是HttpClient和HTTPS;不是来自 GitHub 项目的适用于 Android 的 OAuth。
      【解决方案13】:

      我用过这个,它适用于所有操作系统。

      /**
       * Disables the SSL certificate checking for new instances of {@link HttpsURLConnection} This has been created to
       * aid testing on a local box, not for use on production.
       */
      
      
      private static void disableSSLCertificateChecking() {
          TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
              public X509Certificate[] getAcceptedIssuers() {
                  return null;
              }
      
              @Override
              public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
                  // Not implemented
              }
      
              @Override
              public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
                  // Not implemented
              }
          } };
      
          try {
              SSLContext sc = SSLContext.getInstance("TLS");
      
              sc.init(null, trustAllCerts, new java.security.SecureRandom());
      
              HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
          } catch (KeyManagementException e) {
              e.printStackTrace();
          } catch (NoSuchAlgorithmException e) {
              e.printStackTrace();
          }
      }
      

      【讨论】:

      • 您好@yegor256,我正在使用此代码,但仍然遇到 SSL 握手问题
      【解决方案14】:

      这个用例有很多替代方案。如果您不想在代码库中包含任何自定义代码,例如自定义TrustManager 或自定义SSLSocketFactory,我建议您尝试GitHub - SSLContext Kickstart 和以下代码sn-p:

      <dependency>
          <groupId>io.github.hakky54</groupId>
          <artifactId>sslcontext-kickstart</artifactId>
          <version>7.0.2</version>
      </dependency>
      

      SSL 配置

      SSLFactory sslFactory = SSLFactory.builder()
          .withUnsafeTrustMaterial()
          .withUnsafeHostnameVerifier()
          .build();
      
      SSLSocketFactory sslSocketFactory = sslFactory.getSslSocketFactory();
      

      HttpClient 配置

      HttpParams params = new BasicHttpParams();
      HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
      HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);
      
      SchemeRegistry registry = new SchemeRegistry();
      registry.register(new Scheme("https", sslSocketFactory, 443));
      
      ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry);
      
      HttpClient httpClient = new DefaultHttpClient(ccm, params);
      

      HttpsUrlConnection

      HttpsURLConnection.setDefaultSSLSocketFactory(sslSocketFactory); 
      

      我还需要声明一些免责声明,我是该库的维护者。

      【讨论】:

      • 与许多其他答案相比,这很简单,对我来说效果很好。我能够获取此代码提供的sslSocketFactory 并将其提供给带有.setSSLSocketFactory() 的WebSocket 库(nv-websocket-client)。对我来说唯一不同的是如何指定依赖关系 - 我的 build.gradle 文件有 dependencies{ implementation 'io.github.hakky54:sslcontext-kickstart:6.6.0' } 而不是这个答案中提供的 XML。感谢您的图书馆!
      【解决方案15】:

      只需将 -Dtrust_all_cert=true 添加到 VM 参数即可。这个参数告诉 java 忽略证书检查。

      【讨论】:

      【解决方案16】:

      任何仍在为 Android 2.1 上的 StartCom SSL 证书苦苦挣扎的机构访问 https://www.startssl.com/certs/ 并下载 ca.pem,现在在 @emmby 提供的 answer 中替换

      `export CLASSPATH=bcprov-jdk16-145.jar
       CERTSTORE=res/raw/mystore.bks
            if [ -a $CERTSTORE ]; then
                rm $CERTSTORE || exit 1
            fi
       keytool \
        -import \
        -v \
        -trustcacerts \
        -alias 0 \
        -file <(openssl x509 -in mycert.pem) \
        -keystore $CERTSTORE \
        -storetype BKS \
        -provider org.bouncycastle.jce.provider.BouncyCastleProvider \
        -providerpath /usr/share/java/bcprov.jar \
        -storepass some-password`
      

       `export CLASSPATH=bcprov-jdk16-145.jar
       CERTSTORE=res/raw/mystore.bks
            if [ -a $CERTSTORE ]; then
                rm $CERTSTORE || exit 1
            fi
       keytool \
        -import \
        -v \
        -trustcacerts \
        -alias 0 \
        -file <(openssl x509 -in ca.pem) \
        -keystore $CERTSTORE \
        -storetype BKS \
        -provider org.bouncycastle.jce.provider.BouncyCastleProvider \
        -providerpath /usr/share/java/bcprov.jar \
        -storepass some-password`
      

      应该开箱即用。即使在@emmby 的完美回答之后,我也挣扎了一天多。希望这对某人有所帮助...

      【讨论】:

        【解决方案17】:

        使用这个类

        public class WCFs
        {
            //  https://192.168.30.8/myservice.svc?wsdl
        private static final String NAMESPACE = "http://tempuri.org/";
        private static final String URL = "192.168.30.8";
        private static final String SERVICE = "/myservice.svc?wsdl";
        private static String SOAP_ACTION = "http://tempuri.org/iWCFserviceMe/";
        
        
        public static Thread myMethod(Runnable rp)
        {
            String METHOD_NAME = "myMethod";
        
            SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME);
        
            request.addProperty("Message", "Https WCF Running...");
            return _call(rp,METHOD_NAME, request);
        }
        
        protected static HandlerThread _call(final RunProcess rp,final String METHOD_NAME, SoapObject soapReq)
        {
            final SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
            int TimeOut = 5*1000;
        
            envelope.dotNet = true;
            envelope.bodyOut = soapReq;
            envelope.setOutputSoapObject(soapReq);
        
            final HttpsTransportSE httpTransport_net = new HttpsTransportSE(URL, 443, SERVICE, TimeOut);
        
            try
            {
                HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() // use this section if crt file is handmake
                {
                    @Override
                    public boolean verify(String hostname, SSLSession session)
                    {
                        return true;
                    }
                });
        
                KeyStore k = getFromRaw(R.raw.key, "PKCS12", "password");
                ((HttpsServiceConnectionSE) httpTransport_net.getServiceConnection()).setSSLSocketFactory(getSSLSocketFactory(k, "SSL"));
        
        
            }
            catch(Exception e){}
        
            HandlerThread thread = new HandlerThread("wcfTd"+ Generator.getRandomNumber())
            {
                @Override
                public void run()
                {
                    Handler h = new Handler(Looper.getMainLooper());
                    Object response = null;
        
                    for(int i=0; i<4; i++)
                    {
                        response = send(envelope, httpTransport_net , METHOD_NAME, null);
        
                        try
                        {if(Thread.currentThread().isInterrupted()) return;}catch(Exception e){}
        
                        if(response != null)
                            break;
        
                        ThreadHelper.threadSleep(250);
                    }
        
                    if(response != null)
                    {
                        if(rp != null)
                        {
                            rp.setArguments(response.toString());
                            h.post(rp);
                        }
                    }
                    else
                    {
                        if(Thread.currentThread().isInterrupted())
                            return;
        
                        if(rp != null)
                        {
                            rp.setExceptionState(true);
                            h.post(rp);
                        }
                    }
        
                    ThreadHelper.stopThread(this);
                }
            };
        
            thread.start();
        
            return thread;
        }
        
        
        private static Object send(SoapSerializationEnvelope envelope, HttpTransportSE androidHttpTransport, String METHOD_NAME, List<HeaderProperty> headerList)
        {
            try
            {
                if(headerList != null)
                    androidHttpTransport.call(SOAP_ACTION + METHOD_NAME, envelope, headerList);
                else
                    androidHttpTransport.call(SOAP_ACTION + METHOD_NAME, envelope);
        
                Object res = envelope.getResponse();
        
                if(res instanceof SoapPrimitive)
                    return (SoapPrimitive) envelope.getResponse();
                else if(res instanceof SoapObject)
                    return ((SoapObject) envelope.getResponse());
            }
            catch(Exception e)
            {}
        
            return null;
        }
        
        public static KeyStore getFromRaw(@RawRes int id, String algorithm, String filePassword)
        {
            try
            {
                InputStream inputStream = ResourceMaster.openRaw(id);
                KeyStore keystore = KeyStore.getInstance(algorithm);
                keystore.load(inputStream, filePassword.toCharArray());
                inputStream.close();
        
                return keystore;
            }
            catch(Exception e)
            {}
        
            return null;
        }
        
        public static SSLSocketFactory getSSLSocketFactory(KeyStore trustKey, String SSLAlgorithm)
        {
            try
            {
                TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
                tmf.init(trustKey);
        
                SSLContext context = SSLContext.getInstance(SSLAlgorithm);//"SSL" "TLS"
                context.init(null, tmf.getTrustManagers(), null);
        
                return context.getSocketFactory();
            }
            catch(Exception e){}
        
            return null;
        }
        

        }

        【讨论】:

          【解决方案18】:

          enter image description here

          xamarin android 中的 sspi 失败。

          我找到了这个解决方案;在点击 HTTPS 链接之前输入此代码

          const SslProtocols _Tls12 = (SslProtocols)0x00000C00;
          const SecurityProtocolType Tls12 = (SecurityProtocolType)_Tls12;
          ServicePointManager.SecurityProtocol = Tls12;
          

          【讨论】:

            【解决方案19】:

            使用所有 https

            httpClient = new DefaultHttpClient();
            
            SSLContext ctx = SSLContext.getInstance("TLS");
            X509TrustManager tm = new X509TrustManager() {
                public void checkClientTrusted(X509Certificate[] xcs, String string) throws CertificateException { }
            
                public void checkServerTrusted(X509Certificate[] xcs, String string) throws CertificateException { }
            
                public X509Certificate[] getAcceptedIssuers() {
                    return null;
                }
            };
            
            ctx.init(null, new TrustManager[]{tm}, null);
            SSLSocketFactory ssf = new SSLSocketFactory(ctx, SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
            
            httpClient.getConnectionManager().getSchemeRegistry().register(new Scheme("https", 443, ssf));
            

            【讨论】:

            • 只是重复在这个线程中已经讨论和驳回的同样错误的不安全的非解决方案。
            【解决方案20】:

            上面有很多答案,但我无法让它们中的任何一个正常工作(在我有限的时间内),因此对于处于相同情况的其他人,您可以尝试下面的代码,它非常适合我的 java 测试目的:

                public static HttpClient wrapClient(HttpClient base) {
                try {
                    SSLContext ctx = SSLContext.getInstance("TLS");
                    X509TrustManager tm = new X509TrustManager() {
                        public void checkClientTrusted(X509Certificate[] xcs, String string) throws CertificateException { }
            
                        public void checkServerTrusted(X509Certificate[] xcs, String string) throws CertificateException { }
            
                        public X509Certificate[] getAcceptedIssuers() {
                            return null;
                        }
                    };
                    ctx.init(null, new TrustManager[]{tm}, null);
                    SSLSocketFactory ssf = new SSLSocketFactory(ctx);
                    ssf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
                    ClientConnectionManager ccm = base.getConnectionManager();
                    SchemeRegistry sr = ccm.getSchemeRegistry();
                    sr.register(new Scheme("https", ssf, 443));
                    return new DefaultHttpClient(ccm, base.getParams());
                } catch (Exception ex) {
                    return null;
                }
            }
            

            然后像这样调用:

            DefaultHttpClient baseClient = new DefaultHttpClient();
            HttpClient httpClient = wrapClient(baseClient );
            

            参考:http://tech.chitgoks.com/2011/04/24/how-to-avoid-javax-net-ssl-sslpeerunverifiedexception-peer-not-authenticated-problem-using-apache-httpclient/

            【讨论】:

            • 引用 EJP:“只是重复在此线程中已经讨论和驳回的同样错误的不安全的非解决方案”
            【解决方案21】:

            只需使用这个 -

            public DefaultHttpClient wrapClient(HttpClient base) {
                try {
                    SSLContext ctx = SSLContext.getInstance("TLS");
                    X509TrustManager tm = new X509TrustManager() {
                    public void checkClientTrusted(X509Certificate[] xcs, String string) throws CertificateException { }
            
                    public void checkServerTrusted(X509Certificate[] xcs, String string) throws CertificateException { }
            
                    public X509Certificate[] getAcceptedIssuers() {
                        return null;
                    }
                };
                ctx.init(null, new TrustManager[]{tm}, null);
                SSLSocketFactory ssf = new SSLSocketFactory(ctx);
                ssf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
                ClientConnectionManager ccm = base.getConnectionManager();
                SchemeRegistry sr = ccm.getSchemeRegistry();
                sr.register(new Scheme("https", ssf, 443));
                return new DefaultHttpClient(ccm, base.getParams());
            } catch (Exception ex) {
                return null;
            }
            }
            

            【讨论】:

            • 引用 EJP:“只是重复在此线程中已经讨论和驳回的相同错误的不安全的非解决方案”
            【解决方案22】:

            Daniel's answer 很好,只是我不得不更改此代码...

                SchemeRegistry registry = new SchemeRegistry();
                registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
                registry.register(new Scheme("https", sf, 443));
            
                ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry);
            

            到此代码...

                ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry);
                SchemeRegistry registry = ccm.getShemeRegistry()
                registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
                registry.register(new Scheme("https", sf, 443));
            

            让它工作。

            【讨论】:

            • 这应该如何工作?您甚至在创建注册表之前就引用了它!
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2015-01-31
            • 2014-10-19
            • 1970-01-01
            • 2013-06-04
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多