5

我在通过 Java 与 HTTPS 站点交互时遇到问题。我的程序每次运行时都使用一个带有不受信任证书的 URL。该程序必须在多个系统上运行。目前,我有以下内容:

public class A{
    HostnameVerifier hv = new HostnameVerifier(){
        public boolean verify(String urlHostName, SSLSession session){
            return true;
        }       
    };

    HttpsURLConnection.setDefaultHostnameVerifier(hv);

    javax.net.ssl.TrustManager[] trustAllCerts = new javax.net.ssl.TrustManager[1];
    javax.net.ssl.TrustManager tm = new miTM();
    trustAllCerts[0] = tm;
    javax.net.ssl.SSLContext sc = null;
    try {
        sc = javax.net.ssl.SSLContext.getInstance("SSL");
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    }
    try {
        sc.init(null, trustAllCerts, null);
    } catch (KeyManagementException e) {
        e.printStackTrace();
    }
   javax.net.ssl.HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
}
class miTM implements javax.net.ssl.TrustManager, javax.net.ssl.X509TrustManager{

    public java.security.cert.X509Certificate[] getAcceptedIssuers(){
        return null;
    }

    public boolean isServerTrusted(java.security.cert.X509Certificate[] certs){
        return true;
        }

    public boolean isClientTrusted(java.security.cert.X509Certificate[] certs){
        return true;
    }

    public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) throws java.security.cert.CertificateException{
        return;
    }

    public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType) throws java.security.cert.CertificateException{
        return;
        }
}

使用此代码,我可以很好地执行以下操作:

URL url = new URL(urlString);
URLConnection cnx = url.openConnection();
cnx.connect();

InputStream ins = cnx.getInputStream();
BufferedReader in = new BufferedReader(new InputStreamReader(ins));
String curline;
while( (curline = in.readLine()) != null ) {
     System.out.println(curline);
}

但是,我不能执行以下操作:

httpClient = new HttpClient();
PostMethod postMethod = null;
int intResult = 0;
postMethod = new PostMethod(authURL);
Enumeration emParams = authParams.propertyNames();
while (emParams.hasMoreElements()) {
  String paramName = (String) emParams.nextElement();
  String paramValue = authParams.getProperty(paramName);
     postMethod.addParameter(paramName, paramValue);
}

intResult = httpClient.executeMethod(postMethod);
postMethod.releaseConnection();
ins.close();

执行 executeMethod(postMethod) 时,我得到 SSLHandshakeException、CertPathBuilderException 等。

我能做些什么来解决这个问题?我正在考虑要么接受证书,要么只是绕过​​所有证书验证(因为程序在专用网络内部运行)。

谢谢

4

2 回答 2

5

看起来您正在使用 Apache HttpClient 3。如果这确实是版本 3,您需要按照Apache HttpClient 3 SSL 指南SecureProtocolSocketFactory中的说明构建自己的。这里有一个例子

对于 Apache HttpClient 4,您应该能够将SSLContext构造函数传递给 (HttpClient) SSLSocketFactory,如该问题的答案中所述(包括有关主机名验证的注释)。

但是,一般来说,不要遵循这种方法。通过这样做,您实际上完全禁用了 SSL/TLS 连接的身份验证部分,从而使其容易受到 MITM 攻击。

您应该改为在客户端的信任库中显式导入服务器证书,如本答案中所述。

我正在考虑要么接受证书,要么只是绕过​​所有证书验证(因为程序在专用网络内部运行)。

您的意思是,您愿意仅在您的私有网络内使用 SSL/TLS 进行加密,因为您不够信任它的用户,不会查看可能绕过他们机器的流量,但您也假设这些用户将无法执行 MITM 攻击。这完全没有意义。如果您足够信任他们,您不妨将数据明文发送。如果您不这样做,那么您应该正确实施 SSL/TLS,包括身份验证步骤(证书和主机名验证)。

于 2012-01-30T09:44:27.860 回答
1

HttpClient 4.3:

     HttpClientBuilder cb = HttpClientBuilder.create();
     SSLContextBuilder sslcb = new SSLContextBuilder();
     sslcb.loadTrustMaterial(KeyStore.getInstance(KeyStore.getDefaultType()), new TrustSelfSignedStrategy());
     cb.setSslcontext(sslcb.build());
     CloseableHttpClient httpclient = cb.build();
于 2014-09-02T09:53:18.067 回答