2011-01-19 2 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 핸드 셰이크가 느립니다.

안드로이드에서 정상적인 것인지 아는 사람이 있습니까, 아니면 그렇지 않은 사람이라면 더 빨리 만드는 방법이 있습니까?

감사합니다.

는 21.01.11에서 편집 : 나는 예를 paypal.com:443를 들어, 다른 서버에 연결할 때 핸드 셰이크가 빠른 것을 발견했다

.

하지만 이전에 다른 서버에 연결되었습니다. .NET 서비스가 저에게 작성되었습니다. 이전에 말했듯이, 문제가 서버에 있다고 생각하지 않았습니다. 왜냐하면 내가 iPhone 앱과 연결하면 핸드 셰이크가 빠르기 때문입니다. 이제는 iPhone에서 왜 빠르지, 안드로이드에서는 속도가 느린 지 모르겠습니다. 연결이 설정되면, 나는 .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 대 http 였고 SSL/TLS 요소가 거래에 느린 것을 추가하는 것은 약간 다릅니다.

동일한 프로토콜로 동일한 서버에있는 두 개의 동일한 앱 (https를 사용하는 Android 및 iPhone에 각각 하나씩)이 있습니다. HTTP 둘 다에서 테스트했을 때 https iOS의 응답 속도가 다소 빨라졌지만 내 경우에는 약간 빨랐지만 끔찍한 결과는 아니 었습니다.

+0

예 TLS는 일반적으로 순수 연결보다 느리지 만 속도는 빠르다는 것을 알고 있습니다. 그러나 TLS 핸드 셰이크는 매우 느립니다. 이전에 말한 것처럼 5 초가 아니라 10 초가 걸립니다. – Arthur

2

고정 된 하나의 사전 초기화 된 SecureRandom을 사용하는 대신 연결 당 새 을 사용하고 있습니다. 새로운 SecureRandom()을 만들 때마다 시드 (seeding)를위한 엔트로피 (entropy)를 수집해야합니다 (느린 프로세스). 가 처음 사용될 때까지

SecureRandom의 지연이 getSession()

+0

답장을 보내 주셔서 감사합니다. Jumbogram, 저는 여러분이 말한 것을 시도했습니다. 이제는 생성자에서 초기화되는 SecureRandom 인스턴스를 하나만 사용하고 있습니다. 하지만 얼마나 자주 연결하고 연결을 끊을지라도 socket.getSession()을 실행하는 데 항상 약 10 초가 걸립니다. – Arthur

+0

그것이 나 였다면 패킷 캡처를 시도하고 속도 저하가 어디 있는지 살펴 보겠습니다. 모든 패킷 사이에 1 초입니까? 패킷 (n)과 (n + 1) 사이에 긴 지연이 있습니까? 이런 것들. – Jumbogram

+0

좋은 생각, 나는 그것을 시도 할 것이다. 나는 다른 서버 (예 : paypal.com:443)에 연결할 때 핸드 쉐이크가 빠르다는 것을 알아 냈습니다. 나는 지금 내 게시물을 편집했습니다. .NET 서버에서 뭔가를 변경해야한다고 생각하지만 어쩌면 서버의 인증서에 문제가있는 것 같지 않습니다. – Arthur

-1

문제는 장치가 서버 인증서의 유효성을 검사하는 방식에서 가능성이 높습니다로 호출 할 때까지 발생하지 않는 이유입니다, 아니 자기 씨앗을 수행합니다. 유효성 검사에는 CRL 및 OCSP 응답에 대해 제 3 자에게 연락하는 것이 포함될 수 있습니다. 이런 일이 발생하면 시간이 걸립니다. 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

안드로이드 6에서 내 백엔드 요청을 훨씬 빨리 처리했습니다. 안타깝게도 안드로이드 SDK에 버그가 남아 있습니다. –