如何在Java中禁用证书验证

3
我需要只针对测试目的禁用Java证书验证,因此我了解风险。我使用了以下教程:http://www.rgagnon.com/javadetails/java-fix-certificate-problem-in-HTTPS.html 代码如下:
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.URL;
import java.net.URLConnection;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.security.cert.X509Certificate;

public class Cert {
  public static void main(String[] args) throws Exception {
    /*
     *  fix for
     *    Exception in thread "main" 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
     */
    TrustManager[] trustAllCerts = new TrustManager[] {
       new X509TrustManager() {
          public java.security.cert.X509Certificate[] getAcceptedIssuers() {
            return null;
          }

          public void checkClientTrusted(X509Certificate[] certs, String authType) {  }

          public void checkServerTrusted(X509Certificate[] certs, String authType) {  }

       }
    };

    SSLContext sc = SSLContext.getInstance("SSL");
    sc.init(null, trustAllCerts, new java.security.SecureRandom());
    HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());

    // Create all-trusting host name verifier
    HostnameVerifier allHostsValid = new HostnameVerifier() {
        public boolean verify(String hostname, SSLSession session) {
          return true;
        }
    };
    // Install the all-trusting host verifier
    HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
    /*
     * end of the fix
     */

    URL url = new URL("https://www.nakov.com:2083/");
    URLConnection con = url.openConnection();
    Reader reader = new InputStreamReader(con.getInputStream());
    while (true) {
      int ch = reader.read();
      if (ch==-1) {
        break;
      }
      System.out.print((char)ch);
    }
      }
    }

我仍然遇到以下错误。有人可以帮忙吗?
Exception in thread "main" java.io.IOException: Server returned HTTP response code: 401 for URL: https://www.nakov.com:2083/
    at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1615)
    at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:254)
    at MainProject.Cert.main(Cert.java:56)

我有一段类似的代码,但是当我运行我的应用程序时,它会给我一个错误,说:java.lang.classcastexception: java.lang.string无法转换为java.lang.boolean。我相信这个错误来自于verify(String, SSLSession)方法,在该方法中返回一个布尔值,但由于某种原因,在我的情况下它返回了null?有什么想法吗? - codeinprogress
4个回答

4
“修复”和异常似乎无关:该修复禁用了客户端对服务器证书的验证,而异常表示服务器认为客户端未被授权访问该URL。

但是当我将URL添加到浏览器中后,我可以访问它。唯一的问题是Firefox会警告我该网站使用了自签名证书。 - Jury A
1
然后我会检查Firefox发送的HTTP请求(例如使用Firebug的网络选项卡),以找出差异(cookie?用户代理标头?不同的HTTP代理?...?)。 - meriton

3
这并不能解决问题。401错误是通过HTTPS和SSL传输的,所以证书完美地起作用。
无论如何,我强烈建议您不要这样做。您不希望在测试和生产环境中执行不同的代码。测试代码可能会泄露到生产环境中,从而危及安全性。而且,测试不安全的代码毫无意义。

2

不必在代码中禁用它,只需将证书添加到测试机器的信任存储区,确保您不会发布已禁用检查的构建。


我需要以编程方式完成这个。 - Jury A
1
@JuryA 为什么?你为什么想编写有条件的不安全代码?别这么做。 - user207421
我也必须这样做,因为我正在为多个客户编写软件,将连接到他们自己具有各种不同证书的服务器。我并不真的关心证书,因为链接是完全可信的。 - Eric Darchis
这个争论的双方都是正确的 - 确保证书有效是正确的,但开发人员将不得不持续管理证书 - 如果只有几个证书,那很简单,但当证书数量增加时会怎样?当双向 SSL 开始运行时会发生什么?客户端证书也必须安装在服务器上... 这可能会失控。另一方面,如果有一个集成环境部署了真实证书,并且有自动化测试针对新部署进行测试,那么每个人都是赢家。 - KRK Owner

1

正如其他人所提到的,错误代码401意味着您已经建立了SSL连接,发送了请求并收到了401错误响应。因此,您的SSL代码是正确的。

当您在浏览器中打开此页面时,是否会出现用户名/密码提示?也许是自动登录?如果是这种情况,我会说您的代码缺少基本身份验证或类似功能。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接