2013-06-12 94 views
7

我試圖做出REST API的調用,但我得到以下異常(在年底前完成堆棧跟蹤):如何禁用SSL驗證?

"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" 

我問這個問題的API提供者,並說有什麼不對使用您正在使用的SSL庫。

你會如何解決這個問題?使用這個相同的代碼(下面),我確實沒有問題地調用NIMBLE API REST,但在這種情況下它不起作用。 然後,我沒有任何文件cert(.cer)。

我需要停用SSL驗證,因爲安全方法是我已有的API KEY。

有什麼建議嗎?

非常感謝!

====控制檯:====

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 

我也曾嘗試下面的表格和異常是一樣的:

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 

====代碼:== ==

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); 
     } 
    } 
} 

====完整的堆棧跟蹤:====

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$1$1.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年6月13日解決方案:實現X509TrustManager

添加以下代碼...

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()); 
    } 
} 

...並添加下面的類(實現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) {} 
} 
+0

的Java版本是您使用? – Bruno

+0

嗨,謝謝你的回覆,我看到了你的評論,我用了java6,現在我安裝並配置了java7,但是錯誤仍然是:/ 我得試試你提到的第二個選項。 –

+0

我不得不實現「X509TrustManager」接口(http://docs.oracle.com/javase/6/docs/api/javax/net/ssl/X509TrustManager.html),並升級到java7,這兩件事情是解決方案,現在工作正常。謝謝! –

回答

7

試試這個

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) { 
    } 
} 
+4

請不要在生產環境中使用此代碼,因爲它會禁用所有證書檢查。因此,你的實現很容易受到[MITM攻擊](http://en.wikipedia.org/wiki/Man-in-the-middle_attack)的影響。 –

+1

嗨!感謝您的回覆,我試着用這段代碼,導入javax.net.ssl.TrustManager和javax.net.ssl.X509TrustManager,並且在我的代碼之前調用了這個方法,但是異常仍然是這樣說的。 –

+1

請不要使用此代碼*。即使只是測試它,部署不安全的解決方案也沒有意義。你正在冒着「泄漏」到生產的風險,這將是一個重大的安全漏洞。此外,代碼會忽略異常並違反TrustManager的合同。避免。 – EJP

-2

請使用帶有完整證書鏈的證書。這意味着至少需要根證書。

您只導入了對方的最終證書,實現無法驗證證書鏈。至少需要根證書。

+0

這是不正確的。所有需要的是*任何*的簽名者證書,導入爲'可信'。通常,最高的一個是進口的。同行應該發送鏈的其餘部分連同其證書。 – EJP

+0

@EJP我寫道,至少需要根證書(在第一段中)。我糾正了第二段,澄清了這一點。 –

3

我需要停用SSL驗證,因爲安全方法是 我已有的API密鑰。

目前尚不清楚您認爲API密鑰(及其提供的安全性方面)與SSL/TLS提供的安全性有什麼關係:它們當然不能解決相同的安全問題。 SSL/TLS是關於保護數據傳輸免受竊聽和篡改。

如果您檢查您嘗試與this SSL testing service聯繫的服務器,您會發現服務器需要支持服務器名稱指示(SNI)的客戶端:這允許服務器使用不同證書託管多臺主機。

如果您的客戶端不支持SNI(Java僅在客戶端從版本7支持它),請求將顯示與縮進的不同的證書:證書驗證或主機可能會失敗名稱驗證程序。禁用任何檢查都會使連接容易受到中間人攻擊。

  • 我想說,您遇到的問題的最可能原因是您使用的是不支持SNI的Java版本(例如Java 6)。

  • 您也可能使用的JRE在其默認信任存儲中沒有此特定CA.您可以嘗試從其他來源轉換成您願意信任的CA證書列表(例如Mozilla包,通常建議使用cURL)。您可能需要了解哪些CA證書是第一個。

    作爲JSSE reference guide says

    重要說明:JDK附帶在/ lib /安全/ cacerts文件受信任的根證書 的數量有限。由於keytool中記錄了 ,因此如果您將此 文件用作信任庫,則您有責任維護(即, 添加/刪除)此文件中包含的證書。

    根據您聯繫的服務器的證書配置, 您可能需要添加其他根證書。從相應的供應商處獲取所需的 特定根證書。

無論哪種方式:停用SSL驗證是不是解決你的問題。

編輯:

它看起來像你想使用該服務具有由startssl如果頒發的證書,這是默認情況下不與Oracle JRE顯然捆綁在一起的CA之一。

您需要download it from StartSSL(或將其從您已有的可信軟件包中導出,稱爲「StartCom ...」),並使用keytool將其導入cacerts商店(如果您使用的是其他信任商店不同的一個):

keytool -import -keystore /path/to/jre/lib/security/cacerts -alias startssl -file startssl.crt 

(適應路徑和startssl如果證書文件的要求,當然名稱)