接受 Java 中的证书

发布于 2024-12-29 13:57:25 字数 2686 浏览 1 评论 0原文

我在通过 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 等。

我可以做什么来补救这个问题?我正在考虑接受证书或只是绕过所有证书验证(因为程序在专用网络内部运行)。

谢谢

I'm having problems interacting with an HTTPS site via Java. My program uses one URL with an untrusted certificate each time the program runs. This program has to run on more than one system. Currently, I have the following:

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;
        }
}

With this code, I can perform the following just fine:

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);
}

However, I cannot do the following:

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();

When executeMethod(postMethod) is executed, I get an SSLHandshakeException, CertPathBuilderException, and so on.

What can I do to remedy this? I'm thinking of either accepting the certificate or just bypassing all certificate validation (as the program runs internally within a private network).

Thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

各自安好 2025-01-05 13:57:25

看起来您正在使用 Apache HttpClient 3。如果这确实是版本 3,您需要构建自己的 SecureProtocolSocketFactoryApache HttpClient 3 SSL 指南此处有一个示例

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

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

您应该将服务器证书显式导入到客户端的信任存储中,如 这个答案

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

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

It looks like you're using Apache HttpClient 3. If this is indeed version 3, you need to build your own SecureProtocolSocketFactory as explained in the Apache HttpClient 3 SSL guide. There is an example here.

For Apache HttpClient 4, you should be able to pass an SSLContext to the constructor to the (HttpClient) SSLSocketFactory, as described in the answers to this question (including notes regarding host name verification).

However, generally speaking, don't follow this approach. You're effectively disabling the authentication part of the SSL/TLS connection altogether by doing so, thereby making it vulnerable to MITM attacks.

You should explicitly import the server certificate in your client's trust store instead, as described in this answer.

I'm thinking of either accepting the certificate or just bypassing all
certificate validation (as the program runs internally within a
private network).

What you're saying is that you're willing to use SSL/TLS for encryption only within your private network because you don't trust its users enough not to look at the traffic that may go around their machines, but you're also assuming that these users won't be able to perform a MITM attack. This doesn't quite make sense. If you trust them enough, you might as well send the data in clear. If you don't, then you should implement SSL/TLS properly, including the authentication steps (certificate and host name verification).

拿命拼未来 2025-01-05 13:57:25

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();

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();
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文