如何忽略Java应用程序外部的过期证书? [英] How to ignore expired certificates from outside a Java application?

查看:117
本文介绍了如何忽略Java应用程序外部的过期证书?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们有一个Java应用程序,我们需要忽略过期的自签名证书,但是我们不能修改代码来做到这一点.我想知道是否有一个我们可以在启动时提供的系统属性或环境变量,该变量可以让我们暂时忽略所有过期的证书,或者更具体地讲,并在外部提供我们希望其过期的特定证书忽略了.

任何人都有可行的想法吗?

解决方案

以下是结合"> Java SSL:如何禁用主机名验证.

public class IgnoreExpiredServerCertificateAgent {

    public static void premain(String args, Instrumentation inst) throws Exception {
        TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        tmf.init((KeyStore) null);

        TrustManager[] trustManagers = tmf.getTrustManagers();
        final X509TrustManager origTrustManager = (X509TrustManager) trustManagers[0];

        TrustManager[] wrappedTrustManagers = new TrustManager[]{
                new X509TrustManager() {
                    @Override
                    public X509Certificate[] getAcceptedIssuers() {
                        return origTrustManager.getAcceptedIssuers();
                    }

                    @Override
                    public void checkClientTrusted(X509Certificate[] certs, String authType) throws CertificateException {
                        origTrustManager.checkClientTrusted(certs, authType);
                    }

                    @Override
                    public void checkServerTrusted(X509Certificate[] certs, String authType) throws CertificateException {
                        try {
                            origTrustManager.checkServerTrusted(certs, authType);
                        } catch (CertificateExpiredException ignored) {
                        }
                    }
                }
        };

        //SSLContext sc = SSLContext.getDefault();
        SSLContext sc = SSLContext.getInstance("TLS");
        sc.init(null, wrappedTrustManagers, null);
        HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
    }
}

然后只需将-javaagent:IgnoreExpiredServerCertificateAgent.jar添加到程序的Java启动参数中即可.

另请参见> SSL和TLS及其它们之间的区别Java中的用法 Java 8 SSLContext.getInstance( "TLSv1.2")是什么意思?


还请注意,证书已过期的服务器本身也可能会检查匹配的客户端证书的有效期:

由以下原因引起:javax.net.ssl.SSLHandshakeException:收到致命警报: certificate_expired at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:174) 在 com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:136) 在 com.sun.net.ssl.internal.ssl.SSLSocketImpl.recvAlert(SSLSocketImpl.java:1822) 在 com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1004) 在 com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1188) 在 com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1215) 在 com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1199) 在 sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:434) 在 sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:166) 在 sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1195) 在 java.net.HttpURLConnection.getResponseCode(HttpURLConnection.java:379) 在 sun.net.www.protocol.https.HttpsURLConnectionImpl.getResponseCode(HttpsURLConnectionImpl.java:318)

如果遇到这样的堆栈跟踪信息,那么不接触服务器就无法缓解问题. 正确的解决方案是在将来的到期日后重新颁发证书.

We have a Java application that we need to ignore an expired self-signed cert, however we cannot modify the code to do this. I wondering if there was a System Property or environment variable that we could provide at start up that would allow us to have all expired cert's ignored for now, or even be more specific and provide externally the specific cert that we would like to have the expiration ignored.

Anyone have any ideas that would work?

解决方案

Here is the solution obtained by combining java - ignore expired ssl certificate and Java SSL: how to disable hostname verification.

public class IgnoreExpiredServerCertificateAgent {

    public static void premain(String args, Instrumentation inst) throws Exception {
        TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        tmf.init((KeyStore) null);

        TrustManager[] trustManagers = tmf.getTrustManagers();
        final X509TrustManager origTrustManager = (X509TrustManager) trustManagers[0];

        TrustManager[] wrappedTrustManagers = new TrustManager[]{
                new X509TrustManager() {
                    @Override
                    public X509Certificate[] getAcceptedIssuers() {
                        return origTrustManager.getAcceptedIssuers();
                    }

                    @Override
                    public void checkClientTrusted(X509Certificate[] certs, String authType) throws CertificateException {
                        origTrustManager.checkClientTrusted(certs, authType);
                    }

                    @Override
                    public void checkServerTrusted(X509Certificate[] certs, String authType) throws CertificateException {
                        try {
                            origTrustManager.checkServerTrusted(certs, authType);
                        } catch (CertificateExpiredException ignored) {
                        }
                    }
                }
        };

        //SSLContext sc = SSLContext.getDefault();
        SSLContext sc = SSLContext.getInstance("TLS");
        sc.init(null, wrappedTrustManagers, null);
        HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
    }
}

Then just add -javaagent:IgnoreExpiredServerCertificateAgent.jar to program's java startup arguments.

See also Difference between SSL and TLS and their usage in Java and Java 8 SSLContext.getInstance("TLSv1.2") what does it mean? for appropriate argument for SSLContext.getInstance() in your case.


Also note that the server with expired certificate may also itself check the expiry of the matching client certificate:

Caused by:javax.net.ssl.SSLHandshakeException: Received fatal alert: certificate_expired at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:174) at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:136) at com.sun.net.ssl.internal.ssl.SSLSocketImpl.recvAlert(SSLSocketImpl.java:1822) at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1004) at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1188) at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1215) at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1199) at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:434) at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:166) at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1195) at java.net.HttpURLConnection.getResponseCode(HttpURLConnection.java:379) at sun.net.www.protocol.https.HttpsURLConnectionImpl.getResponseCode(HttpsURLConnectionImpl.java:318)

If you meet such stacktrace then there is no way to mitigate the problem without touching the server. And the proper solution would be to reissue the certificate with future expiry date.

这篇关于如何忽略Java应用程序外部的过期证书?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆