java 如何停用 SSL 验证?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/17066321/
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
How I can deactivate the SSL verification?
提问by Juan Rojas Montserrat
I'm trying to make a call to REST API, but I get the following exception (Complete StackTrace at the end):
我正在尝试调用 REST API,但出现以下异常(最后是完整的 StackTrace):
"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"
I asked the API provider about this problem and says that there is something wrong with the SSL library That you are using.
我向 API 提供商询问了这个问题,并说您使用的 SSL 库有问题。
How would you solve this problem? With this same code (below) I did make calls to the NIMBLE API REST without problems, but in this case it does not work. Then, I do not have any file cert (.cer).
你会如何解决这个问题?使用相同的代码(如下),我确实可以毫无问题地调用 NIMBLE API REST,但在这种情况下它不起作用。然后,我没有任何文件证书(.cer)。
I need deactivate the SSL verification because the security methods is the API KEY that I already have.
我需要停用 SSL 验证,因为安全方法是我已经拥有的 API KEY。
Any suggestions?
有什么建议?
Thank you very much!
非常感谢你!
==== Console: ====
==== 控制台:====
POST https://api.nexalogy.com/project/create?api_key=XXXXXXXXXXXXXXXXXXXX
HTTP Header:"Content-Type" "application/json"
HTTP Body:[{"name":"project1","lang":"en","type":"twitter"}]
api_key:XXXXXXXXXXXXXXXXXXXX
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
I have also tried the following form and exception is the same:
我也尝试过以下形式,例外情况相同:
POST https://api.nexalogy.com/project/create
HTTP Header:"Content-Type" "application/json"
HTTP Header:"api_key" "XXXXXXXXXXXXXXXXXXXX"
HTTP Body:[{"name":"project1","lang":"en","type":"twitter"}]
api_key:XXXXXXXXXXXXXXXXXXXX
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
==== The code: ====
==== 代码:====
package servlet;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/AddProject")
public class AddProject extends HttpServlet {
private static final long serialVersionUID = 1L;
public AddProject() {
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String body="[{\"name\":\"project1\",\"lang\":\"en\",\"type\":\"twitter\"}]";
String api_key="XXXXXXXXXXXXXXXXXXXX";
String str_response="";
String line="";
URL url = new URL("https://api.nexalogy.com/project/create?api_key="+api_key);
try{
HttpURLConnection connection = (HttpURLConnection)url.openConnection();
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type","application/json");
System.out.println("POST https://api.nexalogy.com/project/create?api_key="+api_key);
System.out.println("HTTP Header:"+"\"Content-Type\" \"application/json\"");
System.out.println("HTTP Body:"+body);
System.out.println("api_key:"+api_key);
connection.setUseCaches(false);
connection.setDoInput(true);
connection.setDoOutput(true);
DataOutputStream wr = new DataOutputStream(connection.getOutputStream());
wr.writeBytes(body);
wr.flush();
wr.close();
InputStream is = connection.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader rd = new BufferedReader(isr);
while ((line = rd.readLine()) != null) str_response+= line + '\r';
rd.close();
System.out.println("str_response:"+str_response);
}catch(Exception e){
e.printStackTrace(System.out);
//throw new RuntimeException(e);
}
}
}
==== Complete StackTrace: ====
==== 完整的堆栈跟踪:====
com.sun.jersey.api.client.ClientHandlerException: 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 com.sun.jersey.client.urlconnection.URLConnectionClientHandler.handle(URLConnectionClientHandler.java:131)
at com.sun.jersey.api.client.Client.handle(Client.java:616)
at com.sun.jersey.api.client.WebResource.handle(WebResource.java:559)
at com.sun.jersey.api.client.WebResource.post(WebResource.java:230)
at engine_brandchats.twitter_api_create_project_0_1.Twitter_api_create_project.tREST_2Process(Twitter_api_create_project.java:955)
at engine_brandchats.twitter_api_create_project_0_1.Twitter_api_create_project.tJava_1Process(Twitter_api_create_project.java:635)
at engine_brandchats.twitter_api_create_project_0_1.Twitter_api_create_project.runJobInTOS(Twitter_api_create_project.java:1641)
at engine_brandchats.twitter_api_create_project_0_1.Twitter_api_create_project.main(Twitter_api_create_project.java:1494)
Caused by: 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 com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Unknown Source)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.fatal(Unknown Source)
at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Unknown Source)
at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Unknown Source)
at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(Unknown Source)
at com.sun.net.ssl.internal.ssl.ClientHandshaker.processMessage(Unknown Source)
at com.sun.net.ssl.internal.ssl.Handshaker.processLoop(Unknown Source)
at com.sun.net.ssl.internal.ssl.Handshaker.process_record(Unknown Source)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(Unknown Source)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(Unknown Source)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(Unknown Source)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(Unknown Source)
at sun.net.www.protocol.https.HttpsClient.afterConnect(Unknown Source)
at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(Unknown Source)
at sun.net.www.protocol.http.HttpURLConnection.getOutputStream(Unknown Source)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.getOutputStream(Unknown Source)
at com.sun.jersey.client.urlconnection.URLConnectionClientHandler.getOutputStream(URLConnectionClientHandler.java:203)
at com.sun.jersey.api.client.CommittingOutputStream.commitWrite(CommittingOutputStream.java:117)
at com.sun.jersey.api.client.CommittingOutputStream.write(CommittingOutputStream.java:89)
at sun.nio.cs.StreamEncoder.writeBytes(Unknown Source)
at sun.nio.cs.StreamEncoder.implFlushBuffer(Unknown Source)
at sun.nio.cs.StreamEncoder.implFlush(Unknown Source)
at sun.nio.cs.StreamEncoder.flush(Unknown Source)
at java.io.OutputStreamWriter.flush(Unknown Source)
at java.io.BufferedWriter.flush(Unknown Source)
at com.sun.jersey.core.util.ReaderWriter.writeToAsString(ReaderWriter.java:191)
at com.sun.jersey.core.provider.AbstractMessageReaderWriterProvider.writeToAsString(AbstractMessageReaderWriterProvider.java:128)
at com.sun.jersey.core.impl.provider.entity.StringProvider.writeTo(StringProvider.java:88)
at com.sun.jersey.core.impl.provider.entity.StringProvider.writeTo(StringProvider.java:58)
at com.sun.jersey.api.client.TerminatingClientHandler.writeRequestEntity(TerminatingClientHandler.java:305)
at com.sun.jersey.client.urlconnection.URLConnectionClientHandler._invoke(URLConnectionClientHandler.java:182)
at com.sun.jersey.client.urlconnection.URLConnectionClientHandler.handle(URLConnectionClientHandler.java:129)
... 7 more
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(Unknown Source)
at sun.security.validator.PKIXValidator.engineValidate(Unknown Source)
at sun.security.validator.Validator.validate(Unknown Source)
at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.validate(Unknown Source)
at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted(Unknown Source)
at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted(Unknown Source)
... 35 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(Unknown Source)
at java.security.cert.CertPathBuilder.build(Unknown Source)
... 41 more
EDITED 2013-06-13 Solution: implements X509TrustManager
编辑 2013-06-13 解决方案:实现 X509TrustManager
Add the following code ...
添加以下代码...
HttpsURLConnection connection = (HttpsURLConnection)url.openConnection();
connection.setRequestMethod("POST");
connection.setUseCaches(false);
connection.setDoInput(true);
connection.setDoOutput(true);
if (connection instanceof HttpsURLConnection) {
try {
KeyManager[] km = null;
TrustManager[] tm = {new RelaxedX509TrustManager()};
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, tm, new java.security.SecureRandom());
SSLSocketFactory sf = sslContext.getSocketFactory();
((HttpsURLConnection)connection).setSSLSocketFactory(sf);
System.out.println("setSSLSocketFactory OK!");
}catch (java.security.GeneralSecurityException e) {
System.out.println("GeneralSecurityException: "+e.getMessage());
}
}
... and add the following class (implements X509TrustManager)
...并添加以下类(实现 X509TrustManager)
class RelaxedX509TrustManager implements X509TrustManager {
public boolean isClientTrusted(java.security.cert.X509Certificate[] chain){ return true; }
public boolean isServerTrusted(java.security.cert.X509Certificate[] chain){ return true; }
public java.security.cert.X509Certificate[] getAcceptedIssuers() { return null; }
public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String input) {}
public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String input) {}
}
回答by Aardvocate Akintayo Olusegun
Try this
试试这个
public void disableCertificates() {
TrustManager[] trustAllCerts = new TrustManager[]{
new X509TrustManager() {
@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
@Override
public void checkClientTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}
@Override
public void checkServerTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}
}
};
// Install the all-trusting trust manager
try {
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
} catch (Exception e) {
}
}
回答by Bruno
I need deactivate the SSL verification because the security methods is the API KEY that I already have.
我需要停用 SSL 验证,因为安全方法是我已经拥有的 API KEY。
It's not clear how you think the API key (and the security aspect it offers) has anything to do with the security offered by SSL/TLS: they're certainly not addressing the same security aspects. SSL/TLS is about protecting the data transmission from eavesdropping and alteration.
不清楚您认为 API 密钥(及其提供的安全性方面)与 SSL/TLS 提供的安全性有何关系:它们肯定没有解决相同的安全性方面。SSL/TLS 旨在保护数据传输免遭窃听和篡改。
If you check the server you're trying to contact against this SSL testing service, you'll find that the server requires a client that supports Server Name Indication (SNI): this allows the server to host multiple hosts with different certificates.
如果您根据此 SSL 测试服务检查您尝试联系的服务器,您会发现该服务器需要一个支持服务器名称指示 (SNI) 的客户端:这允许服务器托管具有不同证书的多个主机。
If your client doesn't support SNI (Java only supports it on the client side from version 7), the requests will be presented with a different certificate than the one indented: it may fail either the certificate verification or the host name verification procedures. Disabling either checks makes the connection vulnerable to Man-In-The-Middle attacks.
如果您的客户端不支持 SNI(Java 仅在版本 7 的客户端支持它),则请求将显示与缩进的证书不同的证书:它可能无法通过证书验证或主机名验证程序。禁用任一检查会使连接容易受到中间人攻击。
I'd say the most likely cause for the problem you're having is that you're using a version of Java that doesn't support SNI (e.g. Java 6).
It's also possible that the JRE you're using doesn't have this particular CA in its default trust store. You could try to get an convert a list of CA certificates you're willing to trust from another source (e.g. Mozilla bundle, as often recommended with cURL). You may need to understand what CA certificates are first.
As the JSSE reference guide says:
IMPORTANT NOTE: The JDK ships with a limited number of trusted root certificates in the /lib/security/cacerts file. As documented in keytool, it is your responsibility to maintain (that is, add/remove) the certificates contained in this file if you use this file as a truststore.
Depending on the certificate configuration of the servers you contact, you may need to add additional root certificate(s). Obtain the needed specific root certificate(s) from the appropriate vendor.
我想说您遇到问题的最可能原因是您使用的 Java 版本不支持 SNI(例如 Java 6)。
您正在使用的 JRE 也有可能在其默认信任存储中没有这个特定的 CA。您可以尝试从其他来源(例如 Mozilla 捆绑包,通常建议使用 cURL)获取您愿意信任的 CA 证书列表。您可能需要先了解什么是 CA 证书。
正如JSSE 参考指南所说:
重要说明:JDK 在 /lib/security/cacerts 文件中附带有限数量的受信任根证书。如 keytool 中所述,如果您将此文件用作信任库,则您有责任维护(即添加/删除)此文件中包含的证书。
根据您联系的服务器的证书配置,您可能需要添加额外的根证书。从适当的供应商处获取所需的特定根证书。
Either way: deactivating SSL verification isn't the solution to your problem.
无论哪种方式:停用 SSL 验证都不能解决您的问题。
EDIT:
编辑:
It looks like the service you're trying to use has a certificate issued by StartSSL, which isn't one of the CAs bundled by default with the Oracle JRE apparently.
看起来您尝试使用的服务具有由 StartSSL 颁发的证书,这显然不是默认情况下与 Oracle JRE 捆绑在一起的 CA 之一。
You'll need to download it from StartSSL(or export it from a trusted bundle you already have, it's called "StartCom ...") and import it into your cacerts
store with keytool (or another trust store if you're using a different one):
您需要从 StartSSL 下载它(或从您已有的受信任捆绑包中导出它,它称为“StartCom ...”)并cacerts
使用 keytool将其导入您的商店(或其他信任商店,如果您使用不同的一):
keytool -import -keystore /path/to/jre/lib/security/cacerts -alias startssl -file startssl.crt
(Adapt the path and the name of the startssl certificate file as required, of course.)
(当然,根据需要调整startssl证书文件的路径和名称。)
回答by Uwe Plonus
Please use a certificate with the complete certificate chain. This means at least the root certificate is needed.
请使用具有完整证书链的证书。这意味着至少需要根证书。
You only have imported the end certificate of your counterpart and the implementation cannot verify the certificate chain. At least the root certificate is needed.
您只导入了对方的最终证书,实施无法验证证书链。至少需要根证书。