2012-01-12 19 views
8

自己署名証明書を使用してサーバーに接続しようとしています。私はこのコードを使ってすべての証明書を受け取ります。証明書のホスト名が一致しませんでしたか?

public class CertificateAcceptor { 

    public void initializeTrustManager() { 
     try { 
      SSLContext context = SSLContext.getInstance("SSL"); 
      context.init(null, createTrustManager(), new SecureRandom()); 
      HttpsURLConnection.setDefaultSSLSocketFactory(context.getSocketFactory()); 

     } catch (NoSuchAlgorithmException e) { 
      e.printStackTrace(); 
     } catch (KeyManagementException e) { 
      e.printStackTrace(); 
     } 
    } 

    private TrustManager[] createTrustManager() { 

    TrustManager[] trustAllCerts = new TrustManager[] { 
      new X509TrustManager() { 

       @Override 
       public X509Certificate[] getAcceptedIssuers() { 
        return null; 
       } 

       @Override 
       public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { 
        // leave blank to trust all clients 
       } 

       @Override 
       public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { 
        // leave blank to trust all servers 
        for (X509Certificate c : chain) { 
         System.out.println(c.toString()); 
        } 
       } 

      } 
     }; 
     return trustAllCerts; 
    } 

} 

しかし、それにもかかわらず、私は次のエラーを取得する:

javax.net.ssl.SSLException: hostname in certificate didn't match: <xyz.ch> != <localhost> 
    at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:220) 
    at org.apache.http.conn.ssl.BrowserCompatHostnameVerifier.verify(BrowserCompatHostnameVerifier.java:54) 
    at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:149) 
    at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:130) 
    at org.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java:339) 
    at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:123) 
    at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:147) 
    at org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:108) 
    at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:415) 
    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:641) 
    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:576) 

私は自分の証明書のコードが実行されることを確信しているので、何が問題になる可能性がありますか?

+1

問題はtrustmanagerではありません。ホスト名の検証は、ヒットしようとしているサーバーの証明書に定義されている名前(サーバーのドメイン別名である必要があります)に対して、要求しているURLのドメインをチェックする独立したセキュリティ手順です。あなたのケースでは、使用しているURLの名前とサーバー証明書の名前が一致しません。 –

答えて

7

あなたはあなたにもSSLContextを初期化する必要があるとのPrashantによって回答は、動作しない場合がありSSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER

SSLSocketFactory sf = new SSLSocketFactory(
    SSLContext.getInstance("TLS"), 
    SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); 
Scheme sch = new Scheme("https", 443, sf); 
httpclient.getConnectionManager().getSchemeRegistry().register(sch); 

HttpGet httpget = new HttpGet("https://host/"); 
... 
... 
+6

これは誤った答えです。あなたは 'ext'拡張子を持つキーツール使って、正しい名前を使用して証明書を設定する必要があります ' '' のkeytool -genkeypair \ -keystoreたkeystore.jks \ -dname「CN = OLEKSIYS-W3T、OU =日Javaのシステムのアプリケーションサーバー、O =サン・マイクロシステムズ、L =サンタクララ、ST =カリフォルニア、C = US」\ -keypass changeitと\ -storepass changeitと\ -keyalg RSA \ -keysize 2048 \ -alias s1as \ -ext SAN = DNS:localhost、IP:127.0.0.1 \ -validity 9999 '' ' とhttp://tersesystems.com/2014/03/23/fixing-hostname-verification/ –

+1

これは間違いなくworkse、しかし、@ Wills ntは正しいです。 「すべて許可」アプローチを使用すると、アプリは脆弱になります。あなたはあまりにも一般的ではないが、仕事/フリーランスのプロジェクトには注意が必要なアプリでうまくいくだろう。 – Jacksonkr

+2

@ジャックソンそれはそれよりも悪いです。 FTCは、このようにしてセキュリティを無効にした人々に対して訴訟を提起している。 http://www.ftc.gov/news-events/press-releases/2014/03/fandango-credit-karma-settle-ftc-charges-the-deceived-consumers –

1

を使用することができます。

私はそれのように、

SSLSocketFactory sf=null ; 
     SSLContext sslContext = null; 
     StringWriter writer; 
     try { 
      sslContext = SSLContext.getInstance("TLS") ; 
      sslContext.init(null,null,null); 
     } catch (NoSuchAlgorithmException e) { 
      //<YourErrorHandling> 
     } catch (KeyManagementException e){ 
      //<YourErrorHandling> 
     } 

     try{ 
      sf = new SSLSocketFactory(sslContext, SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); 

     } catch(Exception e) { 
      //<YourErrorHandling> 

    } 
     Scheme scheme = new Scheme("https",443,sf); 
     httpClient.getConnectionManager().getSchemeRegistry().register(scheme); 
15

ALLOW_ALLが正解ではない何かをするだろう。あなたはext拡張子を持つキーツール使って、正しい名前を使用して証明書を設定する必要があります

keytool -genkeypair \ 
    -keystore keystore.jks \ 
    -dname "CN=OLEKSIYS-W3T, OU=Sun Java System Application Server, O=Sun Microsystems, L=Santa Clara, ST=California, C=US" \ 
    -keypass changeit \ 
    -storepass changeit \ 
    -keyalg RSA \ 
    -keysize 2048 \ 
    -alias default \ 
    -ext SAN=DNS:localhost,IP:127.0.0.1 \ 
    -validity 9999 

は詳細についてはhttp://tersesystems.com/2014/03/23/fixing-hostname-verification/を参照してください。

+0

キーストアを生成した後、それを個別に、あるいは 'SSLContext'の一部として初期化しますか?私の[完全な質問]を見る時間があれば(http://stackoverflow.com/questions/30105561/find-or-intialize-the-keystore-needed-to-solve-hostname-in-certificate-didnt-m ) 私はそれをお願い申し上げます。 –

+0

証明書をトラストストアに追加する必要があります。これを行う通常の方法は、keytoolを使用してcacertsに追加するか、システムプロパティjavax.net.ssl.trustStoreを別のトラストストアを指すように設定することです。 –

0

私の問題は、Java SE 6以下がSNIをサポートしていないことです。つまり、1つのIPには1つのSSL証明書しか持たないということです。しかし、私のサーバー上には、異なるSSL証明書を持つ3つの異なるapisがありました。 Java SE 7以上でSNIがサポートされ、すべてがうまくいきました。 (またはサーバー上で1つのAPIのみを実行している)

関連する問題