11

無効な SSL 証明書を使用して、Web サーバーでホストされている HTTP サービスを呼び出す必要があります。開発では、 keytoolを使用して証明書をインポートしていますが、クライアントのインストールごとに証明書が異なるため、バンドルすることはできません。

序文: SSL 検証をスキップするのは本当に見苦しいことですこの特定のケースでは、SSL を必要とせず、システム内の他のすべての通信は単純な HTTP を介して行われます。だから私はMITM攻撃などについて本当に気にしません。データ用の SSL がないため、攻撃者は SSL を破る必要はありません。これは、私が制御できないレガシー システムのサポートです。

と を持つを使用HttpURLConnectionしています。これは、私が試したいくつかの自己署名サーバーでは機能しますが、顧客のサイトでは機能しません。私が得ているエラーは次のとおりです。SSLSocketFactoryNaiveTrustManagerNaiveHostnameVerifier

javax.net.ssl.SSLKeyException: [Security:090477]Certificate chain received from xxxxxxxxxx was not trusted causing SSL handshake failure.
    at com.certicom.tls.interfaceimpl.TLSConnectionImpl.fireException(Unknown Source)
    at com.certicom.tls.interfaceimpl.TLSConnectionImpl.fireAlertSent(Unknown Source)
    at com.certicom.tls.record.handshake.HandshakeHandler.fireAlert(Unknown Source)
    at com.certicom.tls.record.handshake.HandshakeHandler.fireAlert(Unknown Source)
    at com.certicom.tls.record.handshake.ClientStateReceivedServerHello.handle(Unknown Source)
    at com.certicom.tls.record.handshake.HandshakeHandler.handleHandshakeMessage(Unknown Source)
    at com.certicom.tls.record.handshake.HandshakeHandler.handleHandshakeMessages(Unknown Source)
    at com.certicom.tls.record.MessageInterpreter.interpretContent(Unknown Source)
    at com.certicom.tls.record.MessageInterpreter.decryptMessage(Unknown Source)
    at com.certicom.tls.record.ReadHandler.processRecord(Unknown Source)
    at com.certicom.tls.record.ReadHandler.readRecord(Unknown Source)
    at com.certicom.tls.record.ReadHandler.readUntilHandshakeComplete(Unknown Source)
    at com.certicom.tls.interfaceimpl.TLSConnectionImpl.completeHandshake(Unknown Source)
    at com.certicom.tls.record.WriteHandler.write(Unknown Source)
    at com.certicom.io.OutputSSLIOStreamWrapper.write(Unknown Source)
    at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:65)
    at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:123)
    at java.io.FilterOutputStream.flush(FilterOutputStream.java:123)
    at weblogic.net.http.HttpURLConnection.writeRequests(HttpURLConnection.java:154)
    at weblogic.net.http.HttpURLConnection.getInputStream(HttpURLConnection.java:358)
    at weblogic.net.http.SOAPHttpsURLConnection.getInputStream(SOAPHttpsURLConnection.java:37)
    at weblogic.net.http.HttpURLConnection.getResponseCode(HttpURLConnection.java:947)
    at (my own code)

SimpleSocketFactoryのように見えます:

public static final SSLSocketFactory getSocketFactory()
{
    if ( sslSocketFactory == null ) {
        try {
            // get ssl context
            SSLContext sc = SSLContext.getInstance("SSL");

            // Create a trust manager that does not validate certificate chains
            TrustManager[] trustAllCerts = new TrustManager[]{
                new NaiveTrustManager() {
                    public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                        log.debug("getAcceptedIssuers");
                        return new java.security.cert.X509Certificate[0];
                    }
                    public void checkClientTrusted(
                        java.security.cert.X509Certificate[] certs, String authType) {
                        log.debug("checkClientTrusted");
                    }
                    public void checkServerTrusted(
                        java.security.cert.X509Certificate[] certs, String authType) {
                        log.debug("checkServerTrusted");
                    }
                }
            };

            sc.init(null, trustAllCerts, new java.security.SecureRandom());
            // EDIT: fixed the following line that was redeclaring SSLSocketFactory sslSocketFactory, returning null every time. Same result though.
            sslSocketFactory = sc.getSocketFactory();

            HttpsURLConnection.setDefaultSSLSocketFactory(sslSocketFactory);
            // EDIT: The following line has no effect
            //HttpsURLConnection.setDefaultHostnameVerifier(new NaiveHostNameVerifier());

        } catch (KeyManagementException e) {
            log.error ("No SSL algorithm support: " + e.getMessage(), e);
        } catch (NoSuchAlgorithmException e) {
            log.error ("Exception when setting up the Naive key management.", e);
        }
    }
    return sslSocketFactory;
}

にはNaiveHostnameVerifier有効なホストを制限する方法がありますが、null のままなので、基本的に何でも受け入れます。

public class NaiveHostnameVerifier implements HostnameVerifier {
    String[] patterns;

    public NaiveHostnameVerifier () {
        this.patterns=null;
    }

    public NaiveHostnameVerifier (String[] patterns) {
        this.patterns = patterns;
    }

    public boolean verify(String urlHostName,SSLSession session) {
        if (patterns==null || patterns.length==0) {
            return true;
        } else {
            for (String pattern : patterns) {
                if (urlHostName.matches(pattern)) {
                    return true;
                }
            }
            return false;
        }
    }
}

使い方はこんな感じです。

    try {
        conn = (HttpURLConnection)url.openConnection();
        if (conn instanceof HttpsURLConnection) {
                ((HttpsURLConnection)conn).setSSLSocketFactory(SimpleSSLSocketFactory.getSocketFactory());
                // EDIT: added this line, the HV has to be set on connection, not on the factory.
                ((HttpsURLConnection)conn).setHostnameVerifier(new NaiveHostnameVerifier());
        }
        conn.setDoInput(true);
        conn.setDoOutput(true);
        conn.setRequestMethod("POST");
        conn.setRequestProperty("Content-type","application/x-www-form-urlencoded");
        conn.connect();

        StringBuffer sbContent = new StringBuffer();
        // (snip)
        DataOutputStream stream = new DataOutputStream(conn.getOutputStream ());
        stream.writeBytes(sbContent.toString());
        stream.flush();
        stream.close();
    } catch (ClassCastException e) {
        log.error("The URL does not seem to point to a HTTP connection");
        return null;
    } catch (IOException e) {
        log.error("Error accessing the requested URL", e);
        return null;
    }

エラーメッセージを検索しているとき、ほとんどの人は証明書をストアにインポートするだけですが、どの証明書になるかわからないため、実際にはできません。これが機能しない場合の私の唯一の代替手段は、証明書をダウンロードして、暗号化されたコマンドラインよりも簡単な方法で追加できるツールを作成することですが、Java コードで無効な証明書を無視させたいと思います。

何か案が ?

4

2 に答える 2

2

実際、上記のコードには何の問題もありません。問題は Weblogic とこの Certicom TLS モジュールにあるようです。サーバーオプション、SSL、および詳細を見ると、カスタム HostnameVerifier (SSLMBean.HostnameVerifier) を指定できることがわかりますが、証明書の検証を妨害する機能を示唆する唯一の要素は非推奨です。

Weblogic の外部で上記のコードを試してみたところ、うまく機能しました (ただし、投稿の HostnameVerifier は修正されました)。

次に、この他の質問でipolevoyが提案したように、「-DUseSunHttpHandler = true」をWeblogicパラメーターに追加しようとしました。それは働き始めました。

そうは言っても、Oracle Service Bus サーバーで HTTP ハンドラーを切り替えるのは少し危険に思えます。数週間後に副作用が戻ってきて、私を噛む可能性があります...

また、独自の trustStore を定義して、必要なキーを含む jssecacert を指すようにしました。サーバーごとに独自の trustStore 設定があるため、Weblogic によっても無視されました。そのため、必要なキーを手動でインポートするか、Weblogic を自分のストアに向けるよう管理者に依頼することにしています。

于 2012-11-20T22:25:21.087 に答える
0

実際、これは 10.3.5 より前の Weblogic バージョンの既知のバグであり、Oracle から入手可能なパッチがあります。詳細については、My Oracle Support のドキュメント 1474989.1 を参照してください。

上記の修正は、Oracle による非推奨の (ただしサポートされている) 回避策であり、機能しますが、推奨される解決策ではありません。

推奨される解決策は、Oracle の記事に記載されているパッチをダウンロードし、SSL ホスト名ベリファイアを Weblogic 10.3.5 以降の一部でもある新しいものに置き換えることです。サポートに関して Oracle に準拠し続けたい場合は、これが最適な方法です。

于 2014-06-05T06:31:47.693 に答える