5

用例:有一个 Web 服务发布为https://abcd/zz?wsdl

我想做的是查询这个 URI,如果我得到一个有效的 WSDL,我返回一个布尔值“true”,否则返回一个“false”。现在,如果我通过 Chrome 浏览器访问这个 URL,我将不得不手动接受在证书警告上,然后下载 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();
  }
}

我得到一个错误:

线程“主”javax.net.ssl.SSLHandshakeException 中的异常:java.security.cert.CertificateException:在 com.sun.net.ssl.internal.ssl.Alerts.getSSLException 中找不到与 IP 地址 abcd 匹配的主题替代名称(未知来源) 在 com.sun.net.ssl.internal.ssl.SSLSocketImpl.fatal(Unknown Source) 在 com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Unknown Source) 在 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 ) 在 com.sun.net.ssl.internal.ssl.Handshaker.process_record(Unknown Source) 在 com.sun.net.ssl 的 com.sun.net.ssl.internal.ssl.Handshaker.processLoop(Unknown Source)。 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 ) 在 sun.net.www.protocol.http.HttpURLConnection.getInputStream(Unknown Source) at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(Unknown Source) at JavaHttpsExample.main(JavaHttpsExample.java:14) :java.security.cert.CertificateException:在 sun.security.util.HostnameChecker 中找不到与 IP 地址 abcd 匹配的主题替代名称。matchIP(Unknown Source) at sun.security.util.HostnameChecker.match(Unknown Source) at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkIdentity(Unknown Source) at com.sun.net.ssl.internal。 ssl.X509TrustManagerImpl.checkServerTrusted(未知来源)

我已经用 abcd 替换了真实 IP(当然)

4

2 回答 2

14

不要使用已存根的 TrustManager,因为这会使您的应用程序信任所有人。我建议下载该站点提供的证书并将其添加到私有的、受信任的密钥库中。这使您可以为该站点创建一个例外,而无需为所有人​​开绿灯。

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

在 Chrome 中,单击 URL 左侧的锁定图标。然后点击“证书信息”。转到“详细信息”选项卡,然后单击“复制到文件”。将其另存为“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 ...
于 2012-08-16T16:26:30.743 回答
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;
    }

}
于 2012-08-16T16:17:25.280 回答