首页 文章

使用HttpClient通过HTTPS信任所有证书

提问于
浏览
363

最近发布了关于 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

20 回答

  • 404

    Note: Do not implement this in production code you are ever going to use on a network you do not entirely trust. Especially anything going over the public internet.

    你的问题正是我想知道的 . 在我做了一些搜索后,结论如下 .

    在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可能会面临重定向问题,但这超出了主题范围 .

    注意:在您决定信任所有证书之前,您可能应该完全了解该网站,并且不会对最终用户造成损害 .

    事实上,你应该仔细考虑你所承担的风险,包括我非常赞赏的以下评论中提到的黑客模拟网站的影响 . 在某些情况下,虽然可能很难处理所有证书,但您最好知道信任所有证书的隐含缺点 .

  • 10

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

    • 信任所有证书 . 唐't do this, unless you really know what you'正在做 .

    • 创建仅信任您的证书的自定义SSLSocketFactory . 只要您确切知道更新应用程序需要哪些服务器,此功能就可以使用 .

    • 创建一个包含Android的密钥库文件's 1283178 of certificates, then add your own. If any of those certs expire down the road, you are responsible for updating them in your app. I can' t想到这样做的原因 .

    • 创建一个使用内置证书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()]);
            }
        }
    
    }
    
  • 0

    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(); 
        } 
    }
    

    我希望这可以帮助你 .

  • -5

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

    通过信任任何证书,您完全可以接受中间人攻击 . 任何人都可以通过与您和终端服务器 Build 单独的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();
    

    这有一点需要注意 . 证书最终将过期,代码将在此时停止工作 . 您可以通过查看证书轻松确定何时发生这种情况 .

  • 63

    从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());
        }
    
  • 3

    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();
        }
    }
    
  • 3

    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以添加此修复程序 . 注意我的警告!

  • 4

    我正在为那些使用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);
        }
    }
    }
    
  • -4

    信任所有证书对我来说不是一个真正的选择,所以我做了以下操作让HttpsURLConnection信任一个新证书(另见http://nelenkov.blogspot.jp/2011/12/using-custom-certificate-trust-store-on.html) .

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

    • 使用以下代码从/res/raw/geotrust_cert.bks加载Truststore:

    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());
    
  • 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();
        }
    }
    
  • 3

    我看起来回应了“emmby”(11月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

  • -3

    对于那些希望允许所有证书通过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();
        }
    }
    

    }

    希望这有助于某人 .

  • 32

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

    /**
     * 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();
        }
    }
    
  • 17

    任何仍然在Android 2.1上使用StartCom SSL证书的机构访问https://www.startssl.com/certs/并下载ca.pem,现在在answer@emmby替换

    `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的完美回答,我也在奋斗了一天..希望这有助于某人......

  • 0

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

  • -3

    使用这个课程

    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;
    }
    

    }

  • 3

    使用所有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));
    
  • 0

    上面有很多答案,但我无法让它们中的任何一个正常工作(在我有限的时间内),所以对于同样情况下的其他人,你可以尝试下面的代码,它完全适用于我的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/

  • 469

    只需使用此 -

    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;
    }
    }
    
  • 5

    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));
    

    让它工作 .

相关问题