2012-11-20 25 views
10

無効なSSL証明書を使用してWebサーバー上でホストされているHTTPサービスを呼び出す必要があります。デベロッパーでは、キーツールで証明書をインポートしていますが、クライアントのインストールごとに証明書が異なるため、単にそれをバンドルすることはできません。JavaでSSL検証を無視する

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

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が有効なホストを制限する方法がありますが、それはとても基本的に何でも受け入れて、ヌル残っている:

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

証明書(およびホスト名)の検証を無視すると潜在的なMITM攻撃への接続が開かれることに気付きますか?証明書のエラーを無視する必要がある場合、(管理)セキュリティ手順に欠陥があるようです。また、デフォルトのJSSEプロバイダを使用していないため、Certicom TLSオプションを参照する必要があります。 – Bruno

+0

私はMITM攻撃をよく承知しています。実際、誰かがそのネットワーク上でMITM攻撃を行うことができれば、我々は彼がコミュニケーションを傍受するよりもずっと大きな問題を抱えています。最初は、私が証明書を取得したソフトウェアのステップを検討していましたが、ユーザーが検証した場合は、それを保管しておいてください。しかし、これは私が取り組もうとしている小さな問題よりも大きな課題です。私はCerticom TLSオプションを見ていきます。 –

+2

WebLogicはSSLで恐ろしい、恐ろしいことをしてしまいました。彼らはJava標準に従っていません。 – erickson

答えて

2

実際に上記のコードに問題はありません。この問題は、WeblogicとこのCerticom TLSモジュールにあるようだ。私はサーバーオプション、SSL高度を見てみると、私は、カスタムのHostnameVerifier(SSLMBean.HostnameVerifier)が、証明書の検証が推奨されていませんを妨害する能力を示唆して唯一の要素を指定することができることがわかります。

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

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

つまり、Oracle Service BusサーバーでHTTPハンドラを切り替えるのは少し危険です。

また、私自身のtrustStoreを定義し、必要なキーを含むjssecacertを指し示そうとしました。それはWeblogicでも無視されました。なぜなら、Weblogicは各サーバーのtrustStoreを独自に設定しているからです。だから私は管理者に手動で必要なキーをインポートするか、Weblogicを自分の店にポイントするよう依頼しています。

+0

ところで、HostnameVerifierをカスタマイズすることができず、「javax.net.ssl.SSLKeyException:[Security:090504] intranet.company.comから受信した証明書チェーン - xxxxがホスト名の確認に失敗しました。 * .company.comが含まれていますが、予想されるイントラネットドットコムのチェックが入っています。 Weblogic、私はあなたが嫌い​​です。本当です。 –

0

実際、これは10.3未満のWeblogicバージョンの既知のバグです。5には、Oracleから入手可能なパッチがあります。詳細はMy Oracle Supportの文書1474989.1を参照してください。

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

Oracleの記事に記載されているパッチをダウンロードし、SSLホスト名ベリファイアをWeblogic 10.3.5以上の一部である新しいものに置き換えることをお勧めします。サポートに関してOracleに準拠したままにしたい場合は、この方法があります。

関連する問題