Java 带 HTTPS 的 HttpGet:SSLPeerUnverifiedException
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2308774/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
HttpGet with HTTPS : SSLPeerUnverifiedException
提问by Stefan Kendall
Using HttpClient, I receive the following error when attempting to communicate over HTTPS:
使用HttpClient 时,我在尝试通过 HTTPS 进行通信时收到以下错误:
Exception in thread "main" javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated.
线程“main”中的异常 javax.net.ssl.SSLPeerUnverifiedException: peer 未通过身份验证。
Here is my code:
这是我的代码:
URI loginUri = new URI("https://myUrl.asp");
HttpClient httpclient = new DefaultHttpClient();
HttpGet httpget = new HttpGet( loginUri );
HttpResponse response = httpclient.execute( httpget );
How do I suppress or remove this error?
如何抑制或消除此错误?
采纳答案by Stefan Kendall
Using HttpClient 3.x, you need to do this:
使用 HttpClient 3.x,你需要这样做:
Protocol easyHttps = new Protocol("https", new EasySSLProtocolSocketFactory(), 443);
Protocol.registerProtocol("https", easyHttps);
An implementation of EasySSLProtocolSocketFactory can be found here.
EasySSLProtocolSocketFactory 的实现可以在这里找到。
回答by Jonas Andersson
Note: Do not do this in production code, use http instead, or the actual self signed public key as suggested above.
注意:不要在生产代码中执行此操作,而是使用 http 或如上建议的实际自签名公钥。
On HttpClient 4.xx:
在 HttpClient 4.xx 上:
import static org.junit.Assert.assertEquals;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.DefaultHttpClient;
import org.junit.Test;
public class HttpClientTrustingAllCertsTest {
@Test
public void shouldAcceptUnsafeCerts() throws Exception {
DefaultHttpClient httpclient = httpClientTrustingAllSSLCerts();
HttpGet httpGet = new HttpGet("https://host_with_self_signed_cert");
HttpResponse response = httpclient.execute( httpGet );
assertEquals("HTTP/1.1 200 OK", response.getStatusLine().toString());
}
private DefaultHttpClient httpClientTrustingAllSSLCerts() throws NoSuchAlgorithmException, KeyManagementException {
DefaultHttpClient httpclient = new DefaultHttpClient();
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, getTrustingManager(), new java.security.SecureRandom());
SSLSocketFactory socketFactory = new SSLSocketFactory(sc);
Scheme sch = new Scheme("https", 443, socketFactory);
httpclient.getConnectionManager().getSchemeRegistry().register(sch);
return httpclient;
}
private TrustManager[] getTrustingManager() {
TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
@Override
public void checkClientTrusted(X509Certificate[] certs, String authType) {
// Do nothing
}
@Override
public void checkServerTrusted(X509Certificate[] certs, String authType) {
// Do nothing
}
} };
return trustAllCerts;
}
}
回答by Jonas Andersson
Method returning a "secureClient" (in a Java 7 environnement - NetBeans IDE and GlassFish Server: port https by default 3920 ), hope this could help :
返回“secureClient”的方法(在 Java 7 环境中 - NetBeans IDE 和 GlassFish Server:端口 https 默认为 3920 ),希望这可以帮助:
public DefaultHttpClient secureClient() {
DefaultHttpClient httpclient = new DefaultHttpClient();
SSLSocketFactory sf;
KeyStore trustStore;
FileInputStream trustStream = null;
File truststoreFile;
// java.security.cert.PKIXParameters for the trustStore
PKIXParameters pkixParamsTrust;
KeyStore keyStore;
FileInputStream keyStream = null;
File keystoreFile;
// java.security.cert.PKIXParameters for the keyStore
PKIXParameters pkixParamsKey;
try {
trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
truststoreFile = new File(TRUSTSTORE_FILE);
keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keystoreFile = new File(KEYSTORE_FILE);
try {
trustStream = new FileInputStream(truststoreFile);
keyStream = new FileInputStream(keystoreFile);
} catch (FileNotFoundException ex) {
Logger.getLogger(ApacheHttpRestClient.class.getName()).log(Level.SEVERE, null, ex);
}
try {
trustStore.load(trustStream, PASSWORD.toCharArray());
keyStore.load(keyStream, PASSWORD.toCharArray());
} catch (IOException ex) {
Logger.getLogger(ApacheHttpRestClient.class.getName()).log(Level.SEVERE, null, ex);
} catch (CertificateException ex) {
Logger.getLogger(ApacheHttpRestClient.class.getName()).log(Level.SEVERE, null, ex);
}
try {
pkixParamsTrust = new PKIXParameters(trustStore);
// accepts Server certificate generated with keytool and (auto) signed by SUN
pkixParamsTrust.setPolicyQualifiersRejected(false);
} catch (InvalidAlgorithmParameterException ex) {
Logger.getLogger(ApacheHttpRestClient.class.getName()).log(Level.SEVERE, null, ex);
}
try {
pkixParamsKey = new PKIXParameters(keyStore);
// accepts Client certificate generated with keytool and (auto) signed by SUN
pkixParamsKey.setPolicyQualifiersRejected(false);
} catch (InvalidAlgorithmParameterException ex) {
Logger.getLogger(ApacheHttpRestClient.class.getName()).log(Level.SEVERE, null, ex);
}
try {
sf = new SSLSocketFactory(trustStore);
ClientConnectionManager manager = httpclient.getConnectionManager();
manager.getSchemeRegistry().register(new Scheme("https", 3920, sf));
} catch (KeyManagementException ex) {
Logger.getLogger(ApacheHttpRestClient.class.getName()).log(Level.SEVERE, null, ex);
} catch (UnrecoverableKeyException ex) {
Logger.getLogger(ApacheHttpRestClient.class.getName()).log(Level.SEVERE, null, ex);
}
} catch (NoSuchAlgorithmException ex) {
Logger.getLogger(ApacheHttpRestClient.class.getName()).log(Level.SEVERE, null, ex);
} catch (KeyStoreException ex) {
Logger.getLogger(ApacheHttpRestClient.class.getName()).log(Level.SEVERE, null, ex);
}
// use the httpclient for any httpRequest
return httpclient;
}
回答by Barett
This answer follows on to owlsteadand Mat's responses. It applies to SE/EE installations, not ME/mobile/Android SSL.
这个答案是在owlstead和Mat的回答之后。它适用于 SE/EE 安装,不适用于 ME/移动/Android SSL。
Since no one has yet mentioned it, I'll mention the "production way" to fix this: Follow the steps from the AuthSSLProtocolSocketFactory class in HttpClientto update your trust store & key stores.
由于还没有人提到它,我将提到解决此问题的“生产方式”:按照HttpClient 中的AuthSSLProtocolSocketFactory 类中的步骤更新您的信任存储和密钥存储。
- Import a trusted certificate and generate a truststore file
- 导入可信证书并生成信任库文件
keytool -import -alias "my server cert" -file server.crt -keystore my.truststore
keytool -import -alias "my server cert" -file server.crt -keystore my.truststore
- Generate a new key (use the same password as the truststore)
- 生成新密钥(使用与信任库相同的密码)
keytool -genkey -v -alias "my client key" -validity 365 -keystore my.keystore
keytool -genkey -v -alias "my client key" -validity 365 -keystore my.keystore
- Issue a certificate signing request (CSR)
- 发出证书签名请求 (CSR)
keytool -certreq -alias "my client key" -file mycertreq.csr -keystore my.keystore
keytool -certreq -alias "my client key" -file mycertreq.csr -keystore my.keystore
(self-sign or get your cert signed)
Import the trusted CA root certificate
(自签名或让您的证书签名)
导入受信任的 CA 根证书
keytool -import -alias "my trusted ca" -file caroot.crt -keystore my.keystore
keytool -import -alias "my trusted ca" -file caroot.crt -keystore my.keystore
- Import the PKCS#7 file containg the complete certificate chain
- 导入包含完整证书链的 PKCS#7 文件
keytool -import -alias "my client key" -file mycert.p7 -keystore my.keystore
keytool -import -alias "my client key" -file mycert.p7 -keystore my.keystore
- Verify the resultant keystore file's contents
- 验证生成的密钥库文件的内容
keytool -list -v -keystore my.keystore
keytool -list -v -keystore my.keystore
If you don't have a server certificate, generate one in JKS format, then export it as a CRT file. Source: keytool documentation
如果您没有服务器证书,请生成 JKS 格式的证书,然后将其导出为 CRT 文件。来源:keytool 文档
keytool -genkey -alias server-alias -keyalg RSA -keypass changeit
-storepass changeit -keystore my.keystore
keytool -export -alias server-alias -storepass changeit
-file server.crt -keystore my.keystore
回答by Tanuj Kumar
This exception will come in case your server is based on JDK 7 and your client is on JDK 6 and using SSL certificates. In JDK 7 sslv2hello message handshaking is disabled by default while in JDK 6 sslv2hello message handshaking is enabled. For this reason when your client trying to connect server then a sslv2hello message will be sent towards server and due to sslv2hello message disable you will get this exception. To solve this either you have to move your client to JDK 7 or you have to use 6u91 version of JDK. But to get this version of JDK you have to get the
如果您的服务器基于 JDK 7,而您的客户端在 JDK 6 上并使用 SSL 证书,则会出现此异常。在 JDK 7 中 sslv2hello 消息握手默认是禁用的,而在 JDK 6 中 sslv2hello 消息握手是启用的。因此,当您的客户端尝试连接服务器时,将向服务器发送 sslv2hello 消息,并且由于 sslv2hello 消息禁用,您将收到此异常。要解决此问题,您必须将客户端移至 JDK 7,或者必须使用 6u91 版本的 JDK。但是要获得此版本的 JDK,您必须获得
回答by rob345
Your local JVM or remote server may not have the required ciphers. go here
您的本地 JVM 或远程服务器可能没有所需的密码。到这里
https://www.oracle.com/java/technologies/javase-jce8-downloads.html
https://www.oracle.com/java/technologies/javase-jce8-downloads.html
and download the zip file that contains: US_export_policy.jar and local_policy.jar
并下载包含:US_export_policy.jar 和 local_policy.jar 的 zip 文件
replace the existing files (you need to find the existing path in your JVM).
替换现有文件(您需要在 JVM 中找到现有路径)。
on a Mac, my path was here. /Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/jre/lib/security
在 Mac 上,我的路径就在这里。/Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/jre/lib/security
this worked for me.
这对我有用。