最近发布了关于 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 回答
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 .
一个例子是......
并在创建HttpClient实例时使用此类 .
顺便说一句,下面的链接适用于正在寻找HttpURLConnection解决方案的人 . Https Connection Android
我已经在froyo上测试了上述两种解决方案,在我的案例中它们都像魅力一样 . 最后,使用HttpURLConnection可能会面临重定向问题,但这超出了主题范围 .
注意:在您决定信任所有证书之前,您可能应该完全了解该网站,并且不会对最终用户造成损害 .
事实上,你应该仔细考虑你所承担的风险,包括我非常赞赏的以下评论中提到的黑客模拟网站的影响 . 在某些情况下,虽然可能很难处理所有证书,但您最好知道信任所有证书的隐含缺点 .
您基本上有四种可能的解决方案来使用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中缺少哪个证书 . 运行以下命令:
你会看到如下输出:
如您所见,我们的根证书来自Thawte . 转到您的提供商的网站,找到相应的证书 . 对我们来说,它是here,您可以看到我们需要的是版权所有2006 .
如果您使用的是自签名证书,则由于您已拥有签名证书,因此无需执行上一步 .
然后,创建包含缺少的签名证书的密钥库文件 . Crazybob有details how to do this on Android,但想法是做以下事情:
如果您还没有,请从以下位置下载充气城堡提供程序库:http://www.bouncycastle.org/latest_releases.html . 这将在下面的类路径中进行 .
运行命令以从服务器提取证书并创建pem文件 . 在这种情况下,mycert.pem .
然后运行以下命令以创建密钥库 .
您会注意到上面的脚本将结果放在
res/raw/mystore.bks
中 . 现在您有一个文件,您将加载到您的Android应用程序中,提供缺少的证书 .为此,请为SSL方案注册SSLSocketFactory:
要创建SSLSocketFactory:
最后,AdditionalKeyStoresSSLSocketFactory代码接受您的新KeyStore并检查内置KeyStore是否无法验证SSL证书:
在
HttpsURLConnection
之前添加此代码,它将完成 . 我知道了 .我希望这可以帮助你 .
这是一个坏主意 . 信任任何证书只会(非常)比完全不使用SSL更好 . 当你说“我希望我的客户接受任何证书(因为我只指向一台服务器)”时,你就是在假设这意味着以某种方式指向“一台服务器”是安全的,它不在公共网络上 .
通过信任任何证书,您完全可以接受中间人攻击 . 任何人都可以通过与您和终端服务器 Build 单独的SSL连接来代理您的连接 . 然后,MITM可以访问您的整个请求和响应 . 除非您首先不需要SSL(您的消息没有任何敏感信息,并且不进行身份验证),否则您不应盲目信任所有证书 .
您应该考虑使用keytool将公共证书添加到jks,并使用它来构建套接字工厂,例如:
这有一点需要注意 . 证书最终将过期,代码将在此时停止工作 . 您可以通过查看证书轻松确定何时发生这种情况 .
从API 8开始,您可以通过这种方式禁用HttpURLConnection SSL检查以进行测试:
HttpComponents的API已经改变 . 它适用于以下代码 .
https://stackoverflow.com/a/6378872/1553004中的上述代码是正确的,除了它还必须调用主机名验证器:
我明确注册stackoverflow以添加此修复程序 . 注意我的警告!
我正在为那些使用httpclient-4.5的人添加一个响应,也可能适用于4.4 .
信任所有证书对我来说不是一个真正的选择,所以我做了以下操作让HttpsURLConnection信任一个新证书(另见http://nelenkov.blogspot.jp/2011/12/using-custom-certificate-trust-store-on.html) .
获取证书;我通过在Firefox中导出证书(单击小锁图标,获取证书详细信息,单击导出)完成此操作,然后使用portecle导出信任库(BKS) .
使用以下代码从/res/raw/geotrust_cert.bks加载Truststore:
这是一个使用4.1.2 httpclient代码的简单版本 . 然后可以将其修改为您认为合适的任何信任算法 .
我看起来回应了“emmby”(11月16日21:29回答),第4项:“创建一个使用内置证书KeyStore的自定义SSLSocketFactory,但是对于任何失败的东西都会返回备用KeyStore用默认验证 . “
这是一种简化的实现 . 加载系统密钥库并与应用程序密钥库合并 .
一种从JKS转换为BKS的简单模式:
*注意:在Android 4.0(ICS)中,Trust Store已更改,更多信息:http://nelenkov.blogspot.com.es/2011/12/ics-trust-store-implementation.html
对于那些希望允许所有证书通过OAuth工作(用于测试目的)的人,请按照下列步骤操作:
1)在此处下载Android OAuth API的源代码:https://github.com/kaeppler/signpost
2)找到文件“CommonsHttpOAuthProvider”类
3)更改如下:
上面的“MySSLSocketFactory”基于已接受的答案 . 为了使它更容易,这里是完整的类:
}
希望这有助于某人 .
我用过这个,它适用于所有操作系统 .
任何仍然在Android 2.1上使用StartCom SSL证书的机构访问https://www.startssl.com/certs/并下载ca.pem,现在在answer由@emmby替换
同
应该开箱即用 . 即使经过@emmby的完美回答,我也在奋斗了一天..希望这有助于某人......
只需将
-Dtrust_all_cert=true
添加到VM参数即可 . 该参数告诉java忽略证书检查 .使用这个课程
}
使用所有https
上面有很多答案,但我无法让它们中的任何一个正常工作(在我有限的时间内),所以对于同样情况下的其他人,你可以尝试下面的代码,它完全适用于我的java测试目的:
并打电话给:
参考:http://tech.chitgoks.com/2011/04/24/how-to-avoid-javax-net-ssl-sslpeerunverifiedexception-peer-not-authenticated-problem-using-apache-httpclient/
只需使用此 -
Daniel's answer很好,除了我不得不改变这段代码......
这段代码......
让它工作 .