如何使用 Apache HttpClient 处理无效的 SSL 证书?
我知道,关于这个问题有很多不同的问题和很多答案...但我无法理解...
我有: ubuntu-9.10-desktop-amd64 + NetBeans6.7.1 “按原样”安装。代表。 我需要通过 HTTPS 连接到某个网站。为此,我使用 Apache 的 HttpClient。
我从教程中读到:
“一旦正确安装了 JSSE,通过 SSL 的安全 HTTP 通信应该如下
简单如普通 HTTP 通信。” 举一些例子:
HttpClient httpclient = new HttpClient();
GetMethod httpget = new GetMethod("https://www.verisign.com/");
try {
httpclient.executeMethod(httpget);
System.out.println(httpget.getStatusLine());
} finally {
httpget.releaseConnection();
}
到目前为止,我写了这样的内容:
HttpClient client = new HttpClient();
HttpMethod get = new GetMethod("https://mms.nw.ru");
//get.setDoAuthentication(true);
try {
int status = client.executeMethod(get);
System.out.println(status);
BufferedInputStream is = new BufferedInputStream(get.getResponseBodyAsStream());
int r=0;byte[] buf = new byte[10];
while((r = is.read(buf)) > 0) {
System.out.write(buf,0,r);
}
} catch(Exception ex) {
ex.printStackTrace();
}
结果我遇到了一系列错误:
javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1627)
at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:204)
at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:198)
at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:994)
at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:142)
at sun.security.ssl.Handshaker.processLoop(Handshaker.java:533)
at sun.security.ssl.Handshaker.process_record(Handshaker.java:471)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:904)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1132)
at sun.security.ssl.SSLSocketImpl.writeRecord(SSLSocketImpl.java:643)
at sun.security.ssl.AppOutputStream.write(AppOutputStream.java:78)
at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:82)
at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:140)
at org.apache.commons.httpclient.HttpConnection.flushRequestOutputStream(HttpConnection.java:828)
at org.apache.commons.httpclient.HttpMethodBase.writeRequest(HttpMethodBase.java:2116)
at org.apache.commons.httpclient.HttpMethodBase.execute(HttpMethodBase.java:1096)
at org.apache.commons.httpclient.HttpMethodDirector.executeWithRetry(HttpMethodDirector.java:398)
at org.apache.commons.httpclient.HttpMethodDirector.executeMethod(HttpMethodDirector.java:171)
at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:397)
at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:323)
at simpleapachehttp.Main.main(Main.java:41)
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:302)
at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:205)
at sun.security.validator.Validator.validate(Validator.java:235)
at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:147)
at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:230)
at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:270)
at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:973)
... 17 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:191)
at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:255)
at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:297)
... 23 more
我需要做什么来创建最简单的 SSL 连接? (可能没有 KeyManager 和 Trust manager 等。)
I know, there are many different questions and so many answers about this problem... But I can't understand...
I have: ubuntu-9.10-desktop-amd64 + NetBeans6.7.1 installed "as is" from off. rep.
I need connecting to some site over the HTTPS. For this I use Apache's HttpClient.
From tutorial I read:
"Once you have JSSE correctly installed, secure HTTP communication over SSL should be as
simple as plain HTTP communication." And some example:
HttpClient httpclient = new HttpClient();
GetMethod httpget = new GetMethod("https://www.verisign.com/");
try {
httpclient.executeMethod(httpget);
System.out.println(httpget.getStatusLine());
} finally {
httpget.releaseConnection();
}
By now, I write this:
HttpClient client = new HttpClient();
HttpMethod get = new GetMethod("https://mms.nw.ru");
//get.setDoAuthentication(true);
try {
int status = client.executeMethod(get);
System.out.println(status);
BufferedInputStream is = new BufferedInputStream(get.getResponseBodyAsStream());
int r=0;byte[] buf = new byte[10];
while((r = is.read(buf)) > 0) {
System.out.write(buf,0,r);
}
} catch(Exception ex) {
ex.printStackTrace();
}
As a result I have a set of errors:
javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1627)
at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:204)
at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:198)
at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:994)
at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:142)
at sun.security.ssl.Handshaker.processLoop(Handshaker.java:533)
at sun.security.ssl.Handshaker.process_record(Handshaker.java:471)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:904)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1132)
at sun.security.ssl.SSLSocketImpl.writeRecord(SSLSocketImpl.java:643)
at sun.security.ssl.AppOutputStream.write(AppOutputStream.java:78)
at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:82)
at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:140)
at org.apache.commons.httpclient.HttpConnection.flushRequestOutputStream(HttpConnection.java:828)
at org.apache.commons.httpclient.HttpMethodBase.writeRequest(HttpMethodBase.java:2116)
at org.apache.commons.httpclient.HttpMethodBase.execute(HttpMethodBase.java:1096)
at org.apache.commons.httpclient.HttpMethodDirector.executeWithRetry(HttpMethodDirector.java:398)
at org.apache.commons.httpclient.HttpMethodDirector.executeMethod(HttpMethodDirector.java:171)
at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:397)
at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:323)
at simpleapachehttp.Main.main(Main.java:41)
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:302)
at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:205)
at sun.security.validator.Validator.validate(Validator.java:235)
at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:147)
at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:230)
at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:270)
at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:973)
... 17 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:191)
at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:255)
at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:297)
... 23 more
What have I to do to create simplest SSL connection?
(Probably without KeyManager and Trust manager etc. while.)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(17)
https://mms.nw.ru 使用不在默认信任管理器集中的自签名证书。要解决此问题,请执行以下操作之一:
TrustManager
配置SSLContext
(请参见下文)。SSLContext
。下面是一个程序,它创建一个接受任何证书的(几乎没有价值的)SSL 上下文:
https://mms.nw.ru uses a self-signed certificate that's not in the default trust manager set. To resolve the issue, do one of the following:
SSLContext
with aTrustManager
that accepts any certificate (see below).SSLContext
with an appropriate trust store that includes your certificate.Here's a program that creates a (mostly worthless) SSL Context that accepts any certificate:
https://mms.nw.ru 可能使用不是由证书颁发机构颁发的证书。因此,您需要将证书添加到受信任的 Java 密钥存储中,如无法找到有效的证书路径中所述到请求的目标:
https://mms.nw.ru likely uses a certificate not issued by a certification authority. Consequently, you need to add the certificate to your trusted Java key store as explained in unable to find valid certification path to requested target:
除了 Pascal Thivent 的正确答案之外,另一种方法是从 Firefox 保存证书(查看证书 -> 详细信息 -> 导出)或
openssl s_client
并将其导入信任存储区。仅当您有办法验证该证书时才应执行此操作。如果做不到这一点,请在第一次连接时执行此操作,如果证书在后续连接中意外更改,它至少会给您一个错误。
要将其导入到信任存储中,请使用:
默认情况下,默认信任存储应为
$JAVA_HOME/jre/lib/security/cacerts
,其密码应为changeit
,请参阅 JSSE 参考指南了解详情。如果您不想全局允许该证书,而仅允许这些连接使用该证书,则可以为其创建一个
SSLContext
:然后,您需要通过以下方式为 Apache HTTP Client 3.x 设置它:实现一个,如果其
SecureProtocolSocketFactory
使用此SSLContext
。 (此处有示例)。Apache HTTP Client 4.x(除了最早的版本之外)直接支持传递
SSLContext
。In addition to Pascal Thivent's correct answer, another way is to save the certificate from Firefox (View Certificate -> Details -> export) or
openssl s_client
and import it into the trust store.You should only do this if you have a way to verify that certificate. Failing that, do it the first time you connect, it will at least give you an error if the certificate changes unexpectedly on subsequent connections.
To import it in a trust store, use:
By default, the default trust store should be
$JAVA_HOME/jre/lib/security/cacerts
and its password should bechangeit
, see JSSE Reference guide for details.If you don't want to allow that certificate globally, but only for these connections, it's possible to create an
SSLContext
for it:Then, you need to set it up for Apache HTTP Client 3.x by implementing one if its
SecureProtocolSocketFactory
to use thisSSLContext
. (There are examples here).Apache HTTP Client 4.x (apart from the earliest version) has direct support for passing an
SSLContext
.对于 Apache HttpClient 4.5+ 和Java8:
但是如果您的 HttpClient 使用 ConnectionManager 来寻求连接,例如这样:
HttpClients.custom().setSSLSocketFactory(sslConnectionSocketFactory)
无效强>,问题没有解决。因为HttpClient使用指定的connectionManager来寻求连接,而指定的connectionManager还没有注册我们自定义的SSLConnectionSocketFactory。要解决这个问题,应该在connectionManager 中注册定制的SSLConnectionSocketFactory。正确的代码应该是这样的:
For Apache HttpClient 4.5+ & Java8:
But if your HttpClient use a ConnectionManager for seeking connection, e.g. like this:
The
HttpClients.custom().setSSLSocketFactory(sslConnectionSocketFactory)
has no effect, the problem is not resolved.Because that the HttpClient use the specified connectionManager for seeking connection and the specified connectionManager haven't register our customized SSLConnectionSocketFactory. To resolve this, should register the The customized SSLConnectionSocketFactory in the connectionManager. The correct code should like this:
Apache HttpClient 4.5 方式:
注意:
org.apache.http.conn.ssl.SSLContextBuilder
已弃用,org.apache.http.ssl.SSLContextBuilder
code> 是新的(请注意后者的包名称中缺少conn
)。The Apache HttpClient 4.5 way:
NOTE:
org.apache.http.conn.ssl.SSLContextBuilder
is deprecated andorg.apache.http.ssl.SSLContextBuilder
is the new one (noticeconn
missing from the latter's package name).来自 http://hc.apache.org/httpclient-3.x/sslguide.html:
可以在其中找到 MySSLSocketFactory 示例
From http://hc.apache.org/httpclient-3.x/sslguide.html:
Where MySSLSocketFactory example can be found here. It references a
TrustManager
, which you can modify to trust everything (although you must consider this!)想要将答案粘贴到此处:
在 Apache HttpClient 4.5.5
Apache客户端4.5.5如何处理无效的SSL证书?
want to paste the answer here:
in Apache HttpClient 4.5.5
How to handle invalid SSL certificate with Apache client 4.5.5?
一旦您拥有了 Java 证书存储(通过使用上面创建的 great InstallCert 类),您就可以通过在 java 启动时传递“javax.net.ssl.trustStore”参数来让 java 使用它。
前任:
Once you have a Java Cert Store (by using the great InstallCert class created above), you can get java to use it by passing the "javax.net.ssl.trustStore" param at java startup.
Ex:
使用自签名测试证书可能会遇到的另一个问题是:
java.io.IOException: HTTPS 主机名错误: 应该是...
当您尝试访问 HTTPS url 时会发生此错误。您可能已将服务器证书安装到 JRE 的密钥库中。但此错误意味着服务器证书的名称与 URL 中提到的服务器的实际域名不匹配。当您使用非 CA 颁发的证书时,通常会发生这种情况。
此示例演示如何编写忽略证书服务器名称的 HttpsURLConnection DefaultHostnameVerifier:
http:// /www.java-samples.com/showtutorial.php?tutorialid=211
Another issue you may run into with self signed test certs is this:
java.io.IOException: HTTPS hostname wrong: should be ...
This error occurs when you are trying to access a HTTPS url. You might have already installed the server certificate to your JRE's keystore. But this error means that the name of the server certificate does not match with the actual domain name of the server that is mentioned in the URL. This normally happens when you are using a non CA issued certificate.
This example shows how to write a HttpsURLConnection DefaultHostnameVerifier that ignore the certificates server name:
http://www.java-samples.com/showtutorial.php?tutorialid=211
要轻松添加运行时信任的主机而不放弃所有检查,请尝试使用此处的代码:http://code.google.com/p/self-signed-cert-trust-manager/。
For a way to easily add hosts you trust at runtime without throwing out all checks, try the code here: http://code.google.com/p/self-signed-cert-trust-manager/.
EasySSLProtocolSocketFactory 给我带来了问题,所以我最终实现了自己的 ProtocolSocketFactory。
首先你需要注册它:
然后实现 ProtocolSocketFactory:
注意:这是使用 HttpClient 3.1 和 Java 8
EasySSLProtocolSocketFactory was giving me problems so I ended up implementing my own ProtocolSocketFactory.
First you need to register it:
Then implement ProtocolSocketFactory:
Note: This is with HttpClient 3.1 and Java 8
我碰巧遇到了同样的问题,突然之间我的所有进口都丢失了。我尝试删除 .m2 文件夹中的所有内容。并尝试重新导入所有内容,但仍然没有任何效果。
最后,我打开了 IDE 抱怨无法在浏览器中下载的网站。并看到它正在使用的证书,并在我
的密钥库路径中看到 /Library/Java/JavaVirtualMachines/jdk1.8.0_171.jdk/Contents/Home/jre/lib/security/cacerts
特定证书不存在。
因此,您所要做的就是再次将证书放入 JAVA JVM 密钥库中。
可以使用以下命令来完成。
如果要求输入密码,请尝试使用默认密码“changeit”
如果运行上述命令时出现权限错误。
在 Windows 中以管理模式打开它。
在 mac 和 unix 中使用 sudo。
成功添加密钥后,
您可以使用以下命令查看它:
您可以使用 teh 命令仅查看 SHA-1
I happened to face the same issue, all of a sudden all my imports were missing. I tried deleting all the contents in my .m2 folder. And trying to re-import everything , but still nothing worked.
Finally what I did was opened the website for which the IDE was complaining that it couldn't download in my browser. And saw the certificate it was using, and saw in my
Path to my keystore was /Library/Java/JavaVirtualMachines/jdk1.8.0_171.jdk/Contents/Home/jre/lib/security/cacerts
that particular certificate was not there.
So all you have to do is put the certificate into the JAVA JVM keystore again.
It can be done using the below command.
If it asks for password, try the default password 'changeit'
If you get permission error when running the above command.
In windows open it in administration mode.
In mac and unix use sudo.
After you have successfully added the key,
You can view it using :
You can view just the SHA-1 using teh command
此链接 逐步解释您的要求。如果您并不真正关心哪个证书,您可以继续执行以下链接中的过程。
注意您可能需要仔细检查您正在执行的操作,因为这是不安全的操作。
This link explains the requirement you have step by step. If You are not really concerned which certificate you can proceed with the process in below link.
Note You might want to double check what you are doing since, this is a unsafe operation.
对于 HttpClient,我们可以这样做:
For HttpClient, we can do this :
按照下面针对 Java 1.7 给出的说明,使用 InstallCert.java 程序文件创建 SSL 证书。
https://github.com/escline/InstallCert
您必须重新启动 tomcat
follow the instruction given below for Java 1.7, to create an SSL certificate using InstallCert.java program file.
https://github.com/escline/InstallCert
you must restart the tomcat
将以下内容与 DefaultTrustManager 一起使用,它像魅力一样在 httpclient 中工作。非常感谢!! @Kevin 和其他所有贡献者
Used the following along with DefaultTrustManager and it worked in httpclient like charm. Thanks a ton!! @Kevin and every other contributor
我正在使用 httpclient 3.1.X ,这对我有用
}
}
I'm useing httpclient 3.1.X ,and this works for me
}
}