通过 HTTPS 使用 HttpClient 信任所有证书
最近发布了一个有关 Https 上的 HttpClient
的问题(在此处找到) 。我已经取得了一些进展,但也遇到了新问题。与我的上一个问题一样,我似乎找不到适合我的示例。基本上,我希望我的客户端接受任何证书(因为我只指向一台服务器),但我不断收到 javax.net.ssl.SSLException: Not Trusted servercertificate 异常。
所以这这就是我所拥有的:
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
Recently posted a question regarding the HttpClient
over Https (found here). I've made some headway, but I've run into new issues. As with my last problem, I can't seem to find an example anywhere that works for me. Basically, I want my client to accept any certificate (because I'm only ever pointing to one server) but I keep getting a javax.net.ssl.SSLException: Not trusted server certificate exception.
So this is what I have:
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);
}
And here's the error I'm getting:
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
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(22)
基本上有四种潜在的解决方案可以使用 httpclient 修复 Android 上的“不受信任”异常:
这个答案使用了解决方案#4,在我看来这是最强大的。
解决方案是使用可以接受多个 KeyStore 的 SSLSocketFactory,允许您使用自己的证书提供自己的 KeyStore。这允许您加载其他顶级证书,例如某些 Android 设备上可能缺少的 Thawte。它还允许您加载自己的自签名证书。它将首先使用内置的默认设备证书,然后仅在必要时才使用其他证书。
首先,您需要确定密钥库中缺少哪个证书。运行以下命令:
您将看到如下输出:
如您所见,我们的根证书来自 Thawte。访问您的提供商的网站并找到相应的证书。对于我们来说,它就在这里,您可以看到我们需要的就是这个版权所有 2006。
如果您使用自签名证书,则无需执行上一步,因为您已经拥有签名证书。
然后,创建包含缺少的签名证书的密钥库文件。 Crazybob 详细介绍了如何在 Android 上执行此操作,但是我们的想法是执行以下操作:
如果您还没有,请从以下位置下载充气城堡提供程序库: http://www.bouncycastle.org/latest_releases.html。这将出现在下面的类路径中。
运行命令从服务器提取证书并创建 pem 文件。在本例中为 mycert.pem。
然后运行以下命令来创建密钥库。
您会注意到上面的脚本将结果放置在
res/raw/mystore.bks
中。现在您已经有了一个文件,您可以将其加载到 Android 应用程序中,该应用程序提供了缺少的证书。为此,请为 SSL 方案注册 SSLSocketFactory:
创建 SSLSocketFactory:
最后,AdditionalKeyStoresSSLSocketFactory 代码,它接受新的 KeyStore 并检查内置 KeyStore 是否无法验证 SSL 证书:
You basically have four potential solutions to fix a "Not Trusted" exception on Android using httpclient:
This answer uses solution #4, which seems to me to be the most robust.
The solution is to use an SSLSocketFactory that can accept multiple KeyStores, allowing you to supply your own KeyStore with your own certificates. This allows you to load additional top-level certificates such as Thawte that might be missing on some Android devices. It also allows you to load your own self-signed certificates as well. It will use the built-in default device certificates first, and fall back on your additional certificates only as necessary.
First, you'll want to determine which cert you are missing in your KeyStore. Run the following command:
And you'll see output like the following:
As you can see, our root certificate is from Thawte. Go to your provider's website and find the corresponding certificate. For us, it was here, and you can see that the one we needed was the one Copyright 2006.
If you're using a self-signed certificate, you didn't need to do the previous step since you already have your signing certificate.
Then, create a keystore file containing the missing signing certificate. Crazybob has details how to do this on Android, but the idea is to do the following:
If you don't have it already, download the bouncy castle provider library from: http://www.bouncycastle.org/latest_releases.html. This will go on your classpath below.
Run a command to extract the certificate from the server and create a pem file. In this case, mycert.pem.
Then run the following commands to create the keystore.
You'll notice that the above script places the result in
res/raw/mystore.bks
. Now you have a file that you'll load into your Android app that provides the missing certificate(s).To do this, register your SSLSocketFactory for the SSL scheme:
To create your SSLSocketFactory:
And finally, the AdditionalKeyStoresSSLSocketFactory code, which accepts your new KeyStore and checks if the built-in KeyStore fails to validate an SSL certificate:
注意:不要在您将要在不完全信任的网络上使用的生产代码中实现此功能。尤其是通过公共互联网进行的任何事情。
你的问题正是我想知道的。经过一番查找,结论如下。
在 HttpClient 方式中,您应该从 org.apache.http.conn.ssl.SSLSocketFactory 创建一个自定义类,而不是 org.apache.http.conn.ssl.SSLSocketFactory
本身。可以在这篇文章中找到一些线索 自定义 SSL 处理已停止正在开发 Android 2.2 FroYo。
一个例子就像...
并在创建 HttpClient 实例时使用此类。
顺便说一句,下面的链接适用于正在寻找 HttpURLConnection 解决方案的人。
Https Connection Android
我在froyo上测试了以上两种解决方案,它们都在我的情况下工作就像一个魅力。最后,使用 HttpURLConnection 可能会面临重定向问题,但这超出了主题。
注意:在决定信任所有证书之前,您可能应该充分了解该站点并且不会对最终用户造成伤害。
事实上,你应该仔细考虑你所承担的风险,包括我深深赞赏的以下评论中提到的黑客模拟网站的影响。在某些情况下,虽然可能很难管理所有证书,但您最好了解信任所有证书的隐含缺点。
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.
Your question is just what I want to know. After I did some searches, the conclusion is as follows.
In HttpClient way, you should create a custom class from org.apache.http.conn.ssl.SSLSocketFactory, not the one org.apache.http.conn.ssl.SSLSocketFactory
itself. Some clues can be found in this post Custom SSL handling stopped working on Android 2.2 FroYo.
An example is like ...
and use this class while creating instance of HttpClient.
BTW, the link below is for someone who is looking for HttpURLConnection solution.
Https Connection Android
I have tested the above two kinds of solutions on froyo, and they all work like a charm in my cases. Finally, using HttpURLConnection may face the redirect problems, but this is beyond the topic.
Note: Before you decide to trust all certificates, you probably should know the site full well and won't be harmful of it to end-user.
Indeed, the risk you take should be considered carefully, including the effect of hacker's mock site mentioned in the following comments that I deeply appreciated. In some situation, although it might be hard to take care of all certificates, you'd better know the implicit drawbacks to trust all of them.
在
HttpsURLConnection
之前添加此代码即可完成。我得到了它。Add this code before the
HttpsURLConnection
and it will be done. I got it.这是一个坏主意。信任任何证书仅比根本不使用 SSL 好一点点。当您说“我希望我的客户端接受任何证书(因为我只指向一台服务器)”时,您假设这意味着以某种方式指向“一台服务器”是安全的,而它不在公共网络上。
通过信任任何证书,您完全可能遭受中间人攻击。任何人都可以通过与您和终端服务器建立单独的 SSL 连接来代理您的连接。然后 MITM 就可以访问您的整个请求和响应。除非您一开始并不真正需要 SSL(您的消息没有任何敏感信息,并且不进行身份验证),否则您不应该盲目信任所有证书。
您应该考虑使用 keytool 将公共证书添加到 jks,并使用它来构建您的套接字工厂,如下所示:
这有一个需要注意的警告。证书最终会过期,届时代码将停止工作。您可以通过查看证书轻松确定何时会发生这种情况。
This is a bad idea. Trusting any certificate is only (very) slightly better than using no SSL at all. When you say "I want my client to accept any certificate (because I'm only ever pointing to one server)" you are assuming this means that somehow pointing to "one server" is safe, which it's not on a public network.
You are completely open to a man-in-the-middle attack by trusting any certificate. Anyone can proxy your connection by establishing a separate SSL connection with you and with the end server. The MITM then has access to your entire request and response. Unless you didn't really need SSL in the first place (your message has nothing sensitive, and doesn't do authentication) you shouldn't trust all certificates blindly.
You should consider adding the public cert to a jks using keytool, and using that to build your socket factory, such as this:
This has one caveat to watch out for. The certificate will expire eventually, and the code will stop working at that time. You can easily determine when this will happen by looking at the cert.
从 API 8 开始,您可以通过这种方式禁用 HttpURLConnection SSL 检查以进行测试:
You can disable HttpURLConnection SSL checking for testing purposes this way since API 8:
https://stackoverflow.com/a/6378872/1553004 中的代码是正确的,但它还必须调用主机名验证器:
我明确注册了 stackoverflow 以添加此修复程序。留意我的警告!
The code above in https://stackoverflow.com/a/6378872/1553004 is correct, except it MUST also call the hostname verifier:
I signed up to stackoverflow expressly to add this fix. Heed my warning!
我正在为使用 httpclient-4.5 的用户添加响应,并且可能也适用于 4.4。
I'm adding a response for those that use the httpclient-4.5, and probably works for 4.4 as well.
HttpComponents 的 API 已更改。它与下面的代码一起使用。
The API of HttpComponents has got changed. It works with the code below.
信任所有证书对我来说并不是真正的选择,因此我执行了以下操作来让 HttpsURLConnection 信任新证书(另请参阅 http://nelenkov.blogspot.jp/2011/12/using-custom-certificate-trust-store-on.html)。
获得证书;我通过在 Firefox 中导出证书(单击小锁图标,获取证书详细信息,单击导出)来完成此操作,然后使用 portecle 导出信任库 (BKS)。
使用以下代码从 /res/raw/geotrust_cert.bks 加载信任库:
Trusting all certificates was no real alternative for me, so I did the following to get HttpsURLConnection to trust a new certificate (see also http://nelenkov.blogspot.jp/2011/12/using-custom-certificate-trust-store-on.html).
Get the certificate; I got this done by exporting the certificate in Firefox (click on the little lock icon, get certificate details, click export), then used portecle to export a truststore (BKS).
Load the Truststore from /res/raw/geotrust_cert.bks with the following code:
这是使用 4.1.2 httpclient 代码的非常简单的版本。然后可以将其修改为您认为合适的任何信任算法。
Here is a much simple version using 4.1.2 httpclient code. This can then be modified to any trust algorithm you see fit.
我看到了“emmby”(于 2011 年 6 月 16 日在 21:29 回答)的回复,第 4 项:“创建一个使用内置证书 KeyStore 的自定义 SSLSocketFactory,但如果出现任何问题,则依靠备用 KeyStore以验证默认值。”
这是一个简化的实现。加载系统密钥库&与应用程序密钥库合并。
从 JKS 转换为 BKS 的简单模式:
*注意:在 Android 4.0 (ICS) 中,信任存储已更改,更多信息:http://nelenkov.blogspot.com.es/2011/12/ics-trust-store-implementation.html
I'm looked response from "emmby" (answered Jun 16 '11 at 21:29), item #4: "Create a custom SSLSocketFactory that uses the built-in certificate KeyStore, but falls back on an alternate KeyStore for anything that fails to verify with the default."
This is a simplified implementation. Load the system keystore & merge with application keystore.
A simple mode to convert from JKS to BKS:
*Note: In Android 4.0 (ICS) the Trust Store has changed, more info: 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”是基于接受的回答。为了使它更容易,这里是完整的课程:
}
希望这对某人有帮助。
For those who would like to allow all certificates to work (for testing purposes) over OAuth, follow these steps:
1) Download the source code of the Android OAuth API here: https://github.com/kaeppler/signpost
2) Find the file "CommonsHttpOAuthProvider" class
3) Change it as below:
The "MySSLSocketFactory" above is based on the accepted answer. To make it even easier, here goes the complete class:
}
Hope this helps someone.
只需将
-Dtrust_all_cert=true
添加到 VM 参数即可。该参数告诉 java 忽略证书检查。Just adding
-Dtrust_all_cert=true
to VM arguments should do. This argument tells java to ignore certificate checks.我用过这个,它适用于所有操作系统。
I used this and It works for me on all OS.
这个用例有很多替代方案。如果您不想在代码库中包含任何自定义代码,例如自定义
TrustManager
或自定义SSLSocketFactory
我建议尝试 GitHub - SSLContext Kickstart 和以下代码片段:SSL 配置
HttpClient 配置
< strong>HttpsUrlConnection
我还需要给出一些免责声明,我是该库的维护者。您可以在此处查看 40 多个针对 java、kotlin 和 scala 的 http 客户端示例:Http 客户端配置示例
There are a-lot alternatives for this use case. If you don't want to have any custom code in your code base such as custom
TrustManager
or customSSLSocketFactory
I would suggest to try GitHub - SSLContext Kickstart and the following code snippet:SSL configuration
HttpClient configuration
HttpsUrlConnection
I also need to give some disclaimer, I am the maintainer of the library. You can view here 40+ http client examples for java, kotlin and scala: Example Http client configurations
任何仍在 Android 2.1 上使用 StartCom SSL 证书的人请访问 https://www.startssl.com/certs/< /a> 并下载 ca.pem,现在位于 答案 提供的 @emmby 替换
为
应该开箱即用。即使在 @emmby 给出完美答案后,我还是挣扎了一天多。希望这对某人有帮助...
Any body still struggling with StartCom SSL Certificates on Android 2.1 visit https://www.startssl.com/certs/ and download the ca.pem, now in the answer provided by @emmby replace
with
Should work out of the box. I was struggling it for over a day even after a perfect answer by @emmby.. Hope this helps someone...
使用这个类
}
use this class
}
在此处输入图像描述
xamarin android 中的 sspi 失败。
我找到了这个解决方案;在点击 HTTPS 链接之前输入此代码
enter image description here
A sspi failed in xamarin android.
I found this solution; put this code before you hit on an HTTPS link
适用于所有 https
work with all https
上面有很多答案,但我无法让它们中的任何一个正常工作(在我有限的时间内),因此对于处于相同情况的其他人,您可以尝试下面的代码,它非常适合我的 java 测试目的:
并调用类似:
参考:http://tech.chitgoks.com/2011/04/24/how-to-avoid-javax-net-ssl-sslpeerunverifiedException-peer-not-authenticated-problem-using- apache-httpclient/
There a many answers above but I wasn't able to get any of them working correctly (with my limited time), so for anyone else in the same situation you can try the code below which worked perfectly for my java testing purposes:
and call like:
Reference: http://tech.chitgoks.com/2011/04/24/how-to-avoid-javax-net-ssl-sslpeerunverifiedexception-peer-not-authenticated-problem-using-apache-httpclient/
只需使用这个 -
Simply use this -
丹尼尔的回答很好,只是我必须将此代码更改
为此代码...
才能使其正常工作。
Daniel's answer was good except I had to change this code...
to this code...
to get it to work.