【问题标题】:SSLHandshakeException when i try to send a get or post https request from my webapp in tomcat server当我尝试从我的 web 应用程序在 tomcat 服务器中发送 get 或 post https 请求时出现 SSLHandshakeException
【发布时间】:2012-08-24 19:00:46
【问题描述】:

从我的 webapp 在 tomcat 服务器中发送 https 请求时引发以下异常

javax.net.ssl.SSLHandshakeException:sun.security.validator.ValidatorException:PKIX 路径构建失败:sun.security.provider.certpath.SunCertPathBuilderException:无法找到请求目标的有效证书路径

这是我的服务器

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package LBS;


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.HttpURLConnection;
import java.net.Proxy;
import java.net.SocketAddress;
import java.net.URL;
import java.net.URLConnection;
import javax.net.ssl.HttpsURLConnection;
//import javax.net.ssl.SSLContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.cert.X509Certificate;
import javax.net.*;
import javax.net.ssl.*;
import java.security.cert.*;


/**
 *
 * @author Ruwan
 */
public class LBS2 extends HttpServlet {

/** 
 * Processes requests for both HTTP <code>GET</code> and <code>POST</code> methods.
 * @param request servlet request
 * @param response servlet response
 * @throws ServletException if a servlet-specific error occurs
 * @throws IOException if an I/O error occurs
 */
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
    response.setContentType("text/html;charset=UTF-8");
    PrintWriter out = response.getWriter();
    try {
        LBS2 s=new LBS2();
        s.myReq();

    } finally {            
        out.close();
    }
}



public void myReq(){
  System.setProperty("https.proxyHost", "10.48.242.90");
  System.setProperty("https.proxyPort", "3128");
        String uri = "https://somthing.com/abc?username=USERNAME&password=PASWORD";

    try{
        SSLContext sslctx = SSLContext.getInstance("SSL");
        sslctx.init(null, new X509TrustManager[] { new MyTrustManager()}, null);
        HttpsURLConnection.setDefaultSSLSocketFactory(sslctx.getSocketFactory());
        URL url = new URL(uri);
        HttpURLConnection con = (HttpURLConnection) url.openConnection();
        con.setRequestMethod("GET");
        con.setDoOutput(true);
        con.connect();
        if (con.getResponseCode() == HttpsURLConnection.HTTP_OK) {
            BufferedReader br = new BufferedReader(new
            InputStreamReader(con.getInputStream()));
            String line;
            while((line = br.readLine()) != null) {
            System.out.println(line);
            }
            br.close();
        }
        con.disconnect();

        }
        catch(Exception e){
        System.out.println(e.toString());
        }
}


    // <editor-fold defaultstate="collapsed" desc="HttpServlet methods. Click on the +     sign on the left to edit the code.">
    /** 
 * Handles the HTTP <code>GET</code> method.
 * @param request servlet request
 * @param response servlet response
 * @throws ServletException if a servlet-specific error occurs
 * @throws IOException if an I/O error occurs
 */
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
    processRequest(request, response);
}

/** 
 * Handles the HTTP <code>POST</code> method.
 * @param request servlet request
 * @param response servlet response
 * @throws ServletException if a servlet-specific error occurs
 * @throws IOException if an I/O error occurs
 */
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
    processRequest(request, response);
}

/** 
 * Returns a short description of the servlet.
 * @return a String containing servlet description
 */
@Override
public String getServletInfo() {
    return "Short description";
}// </editor-fold>
}


class MyTrustManager implements X509TrustManager {
        @Override
            public void checkClientTrusted(X509Certificate[] chain, String
            authType) {
            }

        @Override
            public void checkServerTrusted(X509Certificate[] chain, String
            authType) {
            }

        @Override
            public X509Certificate[] getAcceptedIssuers() {
            return new X509Certificate[0];
        }
 }    

请帮我找出这段代码中 SSL 证书处理的问题 提前考虑

【问题讨论】:

  • 不,我没有,我会试试看。谢谢@Nishant。也有人可以在运行时告诉我上述代码的错误。它可以在 JVM 中运行的普通 Java 程序中完美运行,但不能作为 webapp 在 Tomcat 服务器中运行
  • 嗯...这很奇怪。理想情况下,如果您连接到相同的 (https) URL,您应该在独立应用程序和 web 应用程序中都看到此异常。我添加了相关部分作为答案,以解释“这是如何发生的”。但我不确定为什么它会依赖于执行此代码的容器。

标签: java security ssl https ssl-certificate


【解决方案1】:

这可能会有所帮助:(摘自http://code.naishe.in/2011/07/looks-like-article-no-more-unable-to.html

你们中的一些人可能熟悉(不是非常用户友好的)异常消息

  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

尝试使用 JSSE 打开与主机的 SSL 连接时。这通常意味着服务器正在使用测试证书(可能使用 keytool 生成),而不是来自知名商业证书颁发机构(如 Verisign 或 GoDaddy)的证书。在这种情况下,Web 浏览器会显示警告对话框,但由于 JSSE 无法假定存在交互式用户,因此默认情况下只会抛出异常。

PS:很期待这样作为答案添加的评论。

【讨论】:

【解决方案2】:

您的信任库不信任服务器的证书。您需要将其从服务器导出并安装在客户端。其他人发布的链接显示了一种方法。真正的问题可能是服务器使用的是自签名证书而不是 CA 签名证书,这只会导致每个客户端都出现此问题。最好的解决方案是花钱解决这个问题。

【讨论】:

    【解决方案3】:

    问题:正常的Java程序运行正常 但是,尽管我使用了相同的方法/代码,但 tomcat 服务器中的 webapp 无法正常工作

    解决方案: 所以我为 SSL 证书配置了 tomcat。 如果有人遇到同样的问题。 只需为 SSL 证书配置 tomcat。

    This will be helpful to configure tomcat for SSL Certificate

    感谢您的所有回答和 cmets。 :)

    【讨论】:

    • 您在连接器级别配置的信任库与您的 web 应用运行时使用的信任库无关(除非您没有配置任何内容并使用默认值)。
    【解决方案4】:

    我在使用来自 symantec 的有效签名通配符证书时遇到了同样的问题。

    首先尝试使用 -Djavax.net.debug=SSL 运行您的 java 应用程序,看看实际发生了什么。

    我最终导入了导致证书链中断的中间证书

    我从 symantec 下载了缺少的中间证书(您可以在 ssl 握手日志中看到缺少证书的下载链接:http://svrintl-g3-aia.verisign.com/SVRIntlG3.cer 在我的例子中)。

    然后我在 java 密钥库中导入了证书。导入中间证书后,我的通配符 ssl 证书终于开始工作了:

    keytool -import -keystore ../jre/lib/security/cacerts -trustcacerts -alias "VeriSign Class 3 International Server CA - G3" -file /pathto/SVRIntlG3.cer
    

    【讨论】:

      【解决方案5】:

      您需要返回 null 以绕过证书验证

          @Override
              public X509Certificate[] getAcceptedIssuers() {
              return null;
          }
      

      【讨论】:

      • 谢谢你的回答,仍然抛出同样的异常:( javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException : 无法找到请求目标的有效认证路径
      • 1.说从此方法返回 null 将“绕过证书验证”是不正确的。 2. 从这个方法返回null 是不正确的:参见Javadoc;这违反了它的合同。 3. 写一个信任任何东西的TrustManager 是不正确的,因为它违反了证书交换的整个目的,并使 SSL 容易受到中间人攻击。 -1.
      猜你喜欢
      • 2018-08-03
      • 1970-01-01
      • 2022-01-02
      • 1970-01-01
      • 2018-06-26
      • 1970-01-01
      • 2012-12-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多