2014-10-01 52 views
1

我在Netbeans 8上有以下Java程序(Servlet),我正在進行HTTP GET併發送一些安全證書。我遇到了很多人討論的最常見的錯誤。它在我使用HTTP時運行良好,但現在URL所指向的服務器已經使用HTTPS。這裏是Netbeans的Apache Tomcat或TomEE日誌上的錯誤:即使在安裝並驗證證書之後仍然出現SSL握手錯誤

================================== =============================================== 我的錯誤:

01-Oct-2014 14:00:08.497 SEVERE [http-apr-8080-exec-8] org.apache.catalina.core.StandardWrapperValve.invoke Servlet.service() for servlet [My_API_Call] in context with path [/testapi] threw exception 
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:1917) 
    at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:301) 
    at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:295) 
    at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1369) 
    at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:156) 
    at sun.security.ssl.Handshaker.processLoop(Handshaker.java:925) 
    at sun.security.ssl.Handshaker.process_record(Handshaker.java:860) 
    at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1043) 
    at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1343) 
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1371) 
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1355) 
    at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:563) 
    at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:185) 
    at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1511) 
    at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1439) 
    at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:254) 
    at My_API_Call.sendHttpRequest(My_API_Call.java:129) 
    at My_API_Call.Group_GET(My_API_Call.java:82) 
    at My_API_Call.doGet(My_API_Call.java:60) 
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:618) 
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:725) 
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:291) 
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) 
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) 
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) 
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) 
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:219) 
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106) 
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:503) 
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:136) 
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79) 
    at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:610) 
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88) 
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:526) 
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1078) 
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:655) 
    at org.apache.coyote.http11.Http11AprProtocol$Http11ConnectionHandler.process(Http11AprProtocol.java:277) 
    at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.doRun(AprEndpoint.java:2381) 
    at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.run(AprEndpoint.java:2370) 
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) 
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) 
    at java.lang.Thread.run(Thread.java:745) 
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:387) 
    at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:292) 
    at sun.security.validator.Validator.validate(Validator.java:260) 
    at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:324) 
    at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:229) 
    at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:124) 
    at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1351) 
    ... 39 more 
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target 
    at sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:145) 
    at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:131) 
    at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:280) 
    at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:382) 
    ... 45 more 

======================================== ========================================== 我的程序:

import java.io.BufferedReader; 
import java.io.IOException; 
import java.io.InputStreamReader; 
import java.io.OutputStreamWriter; 
import java.io.PrintWriter; 
import java.net.URL; 
import java.net.URLConnection; 
import java.net.URLEncoder; 
import java.sql.Date; 
import java.text.DateFormat; 
import java.text.SimpleDateFormat; 
import java.util.ArrayList; 
import java.util.Calendar; 
import java.util.HashMap; 
import java.util.Iterator; 
import java.util.List; 
import java.util.Map; 
import java.util.TimeZone; 
import javax.crypto.Mac; 
import javax.crypto.spec.SecretKeySpec; 
import javax.servlet.ServletException; 
import javax.servlet.annotation.WebServlet; 
import javax.servlet.http.HttpServlet; 
import javax.servlet.http.HttpServletRequest; 
import javax.servlet.http.HttpServletResponse; 
import javax.crypto.Mac; 
import org.apache.commons.codec.binary.Hex; 
import com.sun.org.apache.xerces.internal.impl.dv.util.Base64; 
import com.google.gson.Gson; 
import com.google.gson.GsonBuilder; 
import org.json.JSONObject; 

@WebServlet("/My_API_Call") 
public class My_API_Call extends HttpServlet { 
     public My_API_Call() { 
     super(); 
     } 
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 
     response.setContentType("text/html;charset=UTF-8"); 
     // Allocate a output writer to write the response message into the network socket 
     PrintWriter out = response.getWriter(); 
     // Write the response message, in an HTML page 
     try { 
      out.println("<!DOCTYPE html>"); // HTML 5 
      out.println("<html><head>"); 
      out.println("<meta http-equiv='Content-Type' content='text/html; charset=UTF-8'>"); 
      out.println("<h3>JSON Response</h3>"); 
      out.println(new Gson().toJson(API_GET())); 
      out.println("<head><title>My API Call</title></head>"); 
      out.println("<body>"); 
      // Tabulate the request information 
      out.println("</body></html>"); 
     } 
     finally { 
      out.close(); // Always close the output writer 
     } 
    } 
    public static Object API_GET() throws IOException { 
     String accessKey = "myaccesskey"; 
     String secretKey = "mysecretkey"; 
     String uRLCppList = "https://myapichecking.mydomain.com/webservice/testinggroup/133"; 
     String method = "GET"; 
     java.util.Date currentTime = new java.util.Date(); 
     SimpleDateFormat sdf = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z"); 
     sdf.setTimeZone(TimeZone.getTimeZone("GMT")); 
     String dateTimeString = sdf.format(currentTime); 
     String signature = generateSignature(method, secretKey, dateTimeString); 
     String authorization = accessKey + ":" + signature; 
     Map<String, String> params = new HashMap<String, String>(); 
     String[] result = sendHttpRequest(uRLCppList, "POST", params, dateTimeString, authorization); 
     return result; 
    } 
    public static String[] sendHttpRequest(String requestUrl, String method, Map<String, String> params, String dateTimeString, String authorization) throws IOException { 
     List<String> response = new ArrayList<String>(); 
     StringBuffer requestParams = new StringBuffer(); 
     if (params != null && params.size() > 0) { 
      Iterator<String> paramIterator = params.keySet().iterator(); 
      while (paramIterator.hasNext()) { 
       String key = paramIterator.next(); 
       String value = params.get(key); 
       requestParams.append(URLEncoder.encode(key, "UTF-8")); 
       requestParams.append("=").append(URLEncoder.encode(value, "UTF-8")); 
       requestParams.append("&"); 
      } 
     } 
     URL url = new URL(requestUrl); 
     URLConnection urlConn = url.openConnection(); 
     urlConn.setRequestProperty("accept", "application/json"); 
     urlConn.setRequestProperty("datetime", dateTimeString); 
     urlConn.setRequestProperty("authorization", authorization); 
     urlConn.setUseCaches(false); 
     // the request will return a response 
     urlConn.setDoInput(true); 

     if ("POST".equals(method)) { 
      // set request method to POST 
      urlConn.setDoOutput(true); 
     } else { 
      // set request method to GET 
      urlConn.setDoOutput(false); 
     } 
     if ("POST".equals(method) && params != null && params.size() > 0) { 
      OutputStreamWriter writer = new OutputStreamWriter(urlConn.getOutputStream()); 
      writer.write(requestParams.toString()); 
      writer.flush(); 
     } 
     // reads response, store line by line in an array of Strings 
     BufferedReader reader = new BufferedReader(new InputStreamReader(urlConn.getInputStream())); 

     String line = ""; 
     while ((line = reader.readLine()) != null) { 
      response.add(line); 
     } 
     reader.close(); 
     return (String[]) response.toArray(new String[0]); 
    } 
    public static String generateSignature(String method, String secretKey, String dateTimeString) {   
     String cs = String.format("%s\n\n\n%s\n\n\n", method, dateTimeString); 
     String signature = createSignature(cs, secretKey); 
     return signature; 
    } 
    public static String createSignature(String stringIn, String scretKey) { 
     String fixedData = stringIn.replace('\n', (char)10); 
     // Calculate the hash of the information 
     String digest = hmacSha1(scretKey, fixedData); 
     return digest; 
    } 
    public static String hmacSha1(String key, String value) { 
     try { 
      // Get an hmac_sha1 key from the raw key bytes 
      byte[] keyBytes = key.getBytes("iso-8859-1");   
      SecretKeySpec signingKey = new SecretKeySpec(keyBytes, "HmacSHA1"); 
      // Get an hmac_sha1 Mac instance and initialize with the signing key 
      Mac mac = Mac.getInstance("HmacSHA1"); 
      mac.init(signingKey); 
      // Compute the hmac on input data bytes 
      byte[] rawHmac = mac.doFinal(value.getBytes("iso-8859-1")); 
      // Covert array of Hex bytes to a String 
      return Base64.encode(rawHmac); 
      //return new String(hexBytes, "UTF-8"); 
     } 
     catch (Exception e) { 
      throw new RuntimeException(e); 
     } 
    } 
} 

我已經提到到以下線程,但他們中的大多數人一直在談論如何將證書安裝到信任庫中。我已經在上述URL 指的是「https://myapichecking.mydomain.com/webservice/testinggroup/133」的機器上安裝了證書。舉例來說,它指的是IP XX.XX.X.XXX,所以我已經在那裏安裝了證書,但仍然得到相同的錯誤。

1)Resolving javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed Error?

2)http://www.java-samples.com/showtutorial.php?tutorialid=210

任何想法與我的API調用的問題呢?

回答

2

這裏有很多可能會出錯的地方。 SSL問題可能會非常棘手,但您可以嘗試以下步驟。希望其中一個會爲你解決......

首先,遠程服務器的證書是否有效?證書是否過期?它是否由知名認證機構(CA)簽署?

如果遠程服務器的證書未由知名CA簽名,您確定證書在您的信任庫中?我使用keytool -list -v -keystore <truststore file name>來查看您的信任庫中有哪些證書。如果需要,您還可以將這些信息輸出到一個文件中:keytool -list -v -keystore <truststore file name> > truststore.txt在終端中閱讀比較容易。

您確定您正在使用正確的信任庫運行您的應用程序嗎?除非您正在運行隨Java提供的默認信任庫,否則您需要使用'-Djavax.net.ssl.trustStore =「」-Djavax.net.ssl.trustStorePassword =「changeit」'虛擬機選項。

如果您的信任庫中沒有遠程服務器證書,我建議使用名爲InstallCert的java工具來創建一個新的信任庫,該信任庫中將包含該證書。然後使用上面的虛擬機選項引用新的信任庫。

安全注意事項:

不建議更改默認信任附帶的Java。複製它,根據需要將證書添加到新副本,然後通過虛擬機選項引用新副本。

當接受自簽名或未知的CA簽名的證書時,總是存在潛在的安全問題,只知道您從哪裏獲取證書。

+0

好的,謝謝。我正在研究你提到的各種可能性。 – John 2014-10-02 17:06:42