2011-01-19 26 views
7

SSLSocketを使用してサーバーに接続するAndroidアプリを開発しています。私は似たをしたSSLSocketを使用したTLS接続がAndroid OSで遅い

SSLSession session = socket.getSession(); 

// Connect 
if (socket == null || socket.isClosed() || !socket.isConnected()) { 
    if (socket != null && !socket.isClosed()) 
     socket.close(); 
    Log.i(getClass().toString(), "Connecting..."); 
    if (sslContext == null) { 
     sslContext = SSLContext.getInstance("TLS"); 
     sslContext.init(null, trustAllCerts, new SecureRandom()); 
    } 
    SSLSocketFactory socketFactory = sslContext.getSocketFactory(); 
    socket = (SSLSocket)socketFactory.createSocket(host, port); 
    socket.setSoTimeout(20000); 
    socket.setUseClientMode(true); 
    connected = true; 
    Log.i(getClass().toString(), "Connected."); 
} 

// Secure 
if (connected) { 
    Log.i(getClass().toString(), "Securing..."); 
    SSLSession session = socket.getSession(); 
    secured = session.isValid(); 
    if (secured) { 
     Log.i(getClass().toString(), "Secured."); 
    } 
    else 
     Log.i(getClass().toString(), "Securing failed."); 
} 

問題は、それが約5秒以下の行にTLSハンドシェイクを行うためのより多くのイベントを取るということです。これは私が使用しているコードです。 iPhoneアプリでは、ハンドシェークにはわずか1秒しかかからないので、私が接続しているサーバーに問題がないと思います。それはおそらく上記のコードにあります。接続自体は十分速く、TLSハンドシェイクは遅いです。

Androidで正常かどうかは誰にも分かりませんが、そうでない場合はどうすれば速くできますか?

ありがとうございます。

は21.01.11で編集:

私は、私は別のサーバーに接続したときに握手を例paypal.com:443ため、高速であること、を見出しました。

しかし私は前に別のサーバーに接続していました - 私が書いた.NETサービス。私が前に言ったように、問題はサーバーにあるとは思っていませんでした。なぜなら私がiPhone Appと接続すると、ハンドシェイクが速くなるからです。今はなぜiPhoneで高速で、Androidで遅いのか分かりません。接続が確立された後、私は.NETサーバーで行う唯一のものは、次のとおりです。

Console.WriteLine("New client connected."); 
this.sslStream = new SslStream(tcpClient.GetStream(), true); 
this.sslStream.ReadTimeout = 15000; 
this.sslStream.WriteTimeout = 15000; 

Console.WriteLine("Beginning TLS handshake..."); 
this.sslStream.AuthenticateAsServer(connection.ServerCertificate, false, SslProtocols.Tls, false); 
Console.WriteLine("TLS handshake completed."); 

答えて

0

私はこれに似た何かを行っている、それは無担保接続よりも遅くなります。私の場合はhttps vs httpとされていましたが、SSL/TLSの要因によって取引が遅くなることは少し異なります。

私は、同一のプロトコルを使用して、同じサーバーにAndroidとiPhoneの両方でhttpsを使用する2つの同一のアプリケーションを持っています。私は両方のhttpで私は多かれ少なかれ同じ応答時間を参照してください、httpsのiOSで私の場合はわずかに高速だったが、ひどくはないが表示されます。

+0

はい私はTLSが一般的に純粋な接続よりも遅いが、十分に速いことを知っています。しかし、TLSのハンドシェイクは非常に遅いです、私が前に言ったように5秒ではなく、10秒かかります。 – Arthur

2

1つの静的に事前初期化されたを使用する代わりに、接続ごとに新しいSecureRandomを使用しています。新しいSecureRandom()を作成するたびに、シーディングのためにエントロピーを収集する必要があります(遅いプロセス)。最初getSession()

+0

あなたの返事をありがとうJumbogram、私はあなたが言ったことを試みた、今私はコンストラクタで初期化されるSecureRandomの1つのインスタンスを使用しています。しかし、どのくらい頻繁に接続したり切断したりしても、socket.getSession()を実行するには約10秒かかります。 – Arthur

+0

それが私だったら、パケットをキャプチャして、どこが減速しているかを調べようとします。すべてのパケットの間に1秒ですか?パケット(n)と(n + 1)の間に長い遅延がありますか?このようなこと。 – Jumbogram

+0

良いアイデア、私はそれを試してみます。私は、例えばpaypal.com:443のような別のサーバに接続すると、ハンドシェイクが速いことがわかりました。私の投稿を編集しました。.NETサーバーで何かを変更する必要があると思いますが、おそらく問題はサーバーの証明書にありません。 – Arthur

-1

への呼び出しは、問題がデバイスがサーバ証明書を検証する方法で最も可能性が高いになるまで遅延が発生していない理由である、使用されるまで

のSecureRandomは、自己シードません。検証には、第三者にCRLとOCSP応答を連絡することが含まれます。このような場合は、時間がかかります。 iPhoneはおそらくちょうどセキュリティホールBTWである(少なくともデフォルトで)これをしない。

6

旧バージョンのAndroid SDKにバグがありました。どうやら、それは不必要なDNSの逆引き参照をしています。これが起こらないようにする必要があります。ここに私のために働いた回避策があります。以前は15秒かかりましたが、現在は0〜1秒かかります。それが役に立てば幸い。

ここには、Google issueへのリンクがあります。

boolean connected = false; 
if (socket == null || socket.isClosed() || !socket.isConnected()) { 
    if (socket != null && !socket.isClosed()) { 
     socket.close(); 
    } 

    Log.i(getClass().toString(), "Connecting..."); 
    messages.getText().append("Connecting..."); 
    final KeyStore keyStore = KeyStore.getInstance("BKS"); 
    keyStore.load(getResources().openRawResource(R.raw.serverkey), null); 

    final KeyManagerFactory keyManager = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); 
    keyManager.init(keyStore, null); 
    //keyManager.init(null, null); 

    final TrustManagerFactory trustFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); 
    trustFactory.init(keyStore); 

    sslContext = SSLContext.getInstance("TLS"); 
    sslContext.init(keyManager.getKeyManagers(), trustFactory.getTrustManagers(), rnd); 
    final SSLSocketFactory delegate = sslContext.getSocketFactory(); 
    SocketFactory factory = new SSLSocketFactory() { 
     @Override 
     public Socket createSocket(String host, int port) 
         throws IOException, UnknownHostException { 

      InetAddress addr = InetAddress.getByName(host); 
      injectHostname(addr, host); 
      return delegate.createSocket(addr, port); 
     } 
     @Override 
     public Socket createSocket(InetAddress host, int port) 
         throws IOException { 

      return delegate.createSocket(host, port); 
     } 
     @Override 
     public Socket createSocket(String host, int port, InetAddress localHost, int localPort) 
         throws IOException, UnknownHostException { 

      return delegate.createSocket(host, port, localHost, localPort); 
     } 
     @Override 
     public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) 
         throws IOException { 

      return delegate.createSocket(address, port, localAddress, localPort); 
     } 
     private void injectHostname(InetAddress address, String host) { 
      try { 
       Field field = InetAddress.class.getDeclaredField("hostName"); 
       field.setAccessible(true); 
       field.set(address, host); 
      } catch (Exception ignored) { 
      } 
     } 
     @Override 
     public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException { 

      injectHostname(s.getInetAddress(), host); 
      return delegate.createSocket(s, host, port, autoClose); 
     } 
     @Override 
     public String[] getDefaultCipherSuites() { 
      return delegate.getDefaultCipherSuites(); 
     } 
     @Override 
     public String[] getSupportedCipherSuites() { 
      return delegate.getSupportedCipherSuites(); 
     } 
    }; 
    socket = (SSLSocket)factory.createSocket("192.168.197.133", 9999); 
    socket.setSoTimeout(20000); 
    socket.setUseClientMode(true); 
    connected = true; 
    Log.i(getClass().toString(), "Connected."); 
    messages.getText().append("Connected."); 
} 

// Secure 
if (connected) { 
    Log.i(getClass().toString(), "Securing..."); 
    messages.getText().append("Securing..."); 
    SSLSession session = socket.getSession(); 
    boolean secured = session.isValid(); 
    if (secured) { 
     Log.i(getClass().toString(), "Secured."); 
     messages.getText().append("Secured."); 
    } 
} 
+1

私はこれを行う方法をいたるところで探しています(Javaプロジェクトで逆DNSルックアップを無効にする必要があるだけで、アンドロイド関連ではありません)。私は最新のJDKのためにそれを修正しなければなりませんでした。 'hostName'を' InetAddressHolder'ラッパークラスの内部に深く入れました(アクセス不可能で、それを越えるためにはより多くのリフレクションが必要でした)。まだ - ありがとう。 –

+1

ありがとうございます。問題は長い間私に悩まされています。 – SalutonMondo

+0

Android 6で私のバックエンドリクエストをもっと速くしましたが、残念ながらAndroid SDKにはまだバグが残っているようです。 –

関連する問題