如何绕过Java Web服务客户端中的证书检查

时间:2012-08-16 16:06:32

标签: java https wsdl

用例: 有一个名为https://a.b.c.d/zz?wsdl

的网络服务

我想要做的是查询这个URI,如果我得到一个VALID WSDL,我返回一个布尔“true”,否则为“false”。 现在,如果我通过Chrome浏览器访问此URL,我将不得不手动对cert警告进行接受,然后下载WSDL。但是如何通过Java / HttpsURLConnection

来做到这一点
import java.net.URL;
import java.io.*;
import javax.net.ssl.HttpsURLConnection;

public class JavaHttpsExample
{
  public static void main(String[] args)
  throws Exception
  {
    String httpsURL = "https://a.b.c.d/zz/V2.0/api?wsdl";
    URL myurl = new URL(httpsURL);
    HttpsURLConnection con = (HttpsURLConnection)myurl.openConnection();
    InputStream ins = con.getInputStream();
    InputStreamReader isr = new InputStreamReader(ins);
    BufferedReader in = new BufferedReader(isr);

    String inputLine;

    while ((inputLine = in.readLine()) != null)
    {
      System.out.println(inputLine);
    }

    in.close();
  }
}

我收到一个错误:

  

线程“main”中的异常javax.net.ssl.SSLHandshakeException:   java.security.cert.CertificateException:没有主题替代名称   匹配的IP地址a.b.c.d在   com.sun.net.ssl.internal.ssl.Alerts.getSSLException(未知来源)     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)     在   com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(未知   来源)at   com.sun.net.ssl.internal.ssl.ClientHandshaker.processMessage(未知   来源)at   com.sun.net.ssl.internal.ssl.Handshaker.processLoop(未知来源)     在com.sun.net.ssl.internal.ssl.Handshaker.process_record(未知   来源)at   com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(未知来源)     在   com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(未知   来源)at   com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(未知   来源)at   com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(未知   来源)at   sun.net.www.protocol.https.HttpsClient.afterConnect(未知来源)     在   sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(未知   来源)at   sun.net.www.protocol.http.HttpURLConnection.getInputStream(未知   来源)at   sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(未知   来自JavaHttpsExample.main(JavaHttpsExample.java:14)引起的:   java.security.cert.CertificateException:没有主题替代名称   匹配的IP地址a.b.c.d在   sun.security.util.HostnameChecker.matchIP(未知来源)at   sun.security.util.HostnameChecker.match(未知来源)at   com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkIdentity(未知   来源)at   com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted(未知   源)

我用a.b.c.d(当然)取代了真正的IP

2 个答案:

答案 0 :(得分:14)

不要使用存根的TrustManager,因为这会使您的应用程序信任 所有人 。我建议下载该站点提供的证书并将其添加到私有的可信密钥库。这使您可以为该网站制作例外情况,而无需对所有人进行绿灯处理。

我也喜欢这种方法,因为它不需要更改代码。

在Chrome中,点击网址左侧的锁定图标。然后单击“证书信息”。转到“详细信息”选项卡,然后单击“复制到文件”。将其保存为“base64编码的X.509(.cer)”到“SITENAME.cer”。

将$ JAVA_HOME / lib / security / cacerts复制到您的应用程序目录“mykeystore.jks”。

使用以下命令安装证书:

keytool -keystore mykeystore.jks -storepass changeit -importcert -alias SITENAME -trustcacerts -file SITE.cer

现在,当您运行应用程序时,请告诉它使用私有证书存储:

java -Djavax.net.ssl.trustStore=mykeystore.jks ...

答案 1 :(得分:7)

只需实现您自己的信任管理器,如下面的代码

import java.net.URL;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.io.*;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

public class JavaHttpsExample
{
  public static void main(String[] args)
  throws Exception
  {
    String httpsURL = "https://a.b.c.d/zz?wsdl";
    URL myurl = new URL(httpsURL);
    SSLContext ssl = SSLContext.getInstance("TLSv1");
    ssl.init(null, new TrustManager[]{new SimpleX509TrustManager()}, null);
    SSLSocketFactory factory = ssl.getSocketFactory();


    HttpsURLConnection con = (HttpsURLConnection)myurl.openConnection();
    con.setSSLSocketFactory(factory);
    InputStream ins = con.getInputStream();
    InputStreamReader isr = new InputStreamReader(ins);
    BufferedReader in = new BufferedReader(isr);

    String inputLine;

    while ((inputLine = in.readLine()) != null)
    {
      System.out.println(inputLine);
    }

    in.close();
  }
}

class SimpleX509TrustManager implements X509TrustManager {
    public void checkClientTrusted(
            X509Certificate[] cert, String s)
            throws CertificateException {
    }

    public void checkServerTrusted(
            X509Certificate[] cert, String s)
            throws CertificateException {
      }

    @Override
    public X509Certificate[] getAcceptedIssuers() {
        // TODO Auto-generated method stub
        return null;
    }

}