Проблема, скорее всего, заключается в том, как устройство проверяет сертификаты сервера. Валидация может включать контакт со сторонними организациями для получения списков отзыва сертификатов и ответов OCSP. Если это произойдет, это займет время. iPhone, вероятно, просто не делает этого (по крайней мере, по умолчанию), что является дырой в безопасности.

рабатываю приложение для Android, которое использует SSLSocket для подключения к серверу. Это код, который я использую:

// 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.");
}

Проблема заключается в том, что для установления связи TLS в следующей строке требуется около 5 секунд или более.

SSLSession session = socket.getSession();

Я сделал подобное приложение для iPhone, рукопожатие занимает всего 1 секунду, поэтому я думаю, что проблема не в сервере, к которому я подключаюсь, а, возможно, в приведенном выше коде. Само соединение достаточно быстрое, просто TLS-соединение происходит медленно.

Кто-нибудь знает, нормально ли это в Android или нет, как сделать это быстрее?

Спасибо.

ИЗДАНО 21.01.11:

Я обнаружил, что рукопожатие быстро, когда я подключаюсь к другому серверу, напримерpaypal.com:443.

Но раньше я подключался к другому серверу - службе .NET, написанной мной. Как я уже говорил ранее, я не думал, что проблема была в том сервере, потому что, если я подключаюсь к нему с помощью приложения для iPhone, рукопожатие происходит быстро. Теперь я не знаю, почему это быстро на 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.");

Ответы на вопрос(1)

он делает ненужный обратный поиск DNS. Вы должны предотвратить это. Вот обходной путь, который работал для меня. Раньше это занимало 15 секунд, теперь это занимает 0-1 секунд. Надеюсь, это поможет.

Вот ссылка на Googleвопрос.

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.");
    }
}
 SalutonMondo04 июл. 2014 г., 09:01
Спасибо Юйо. проблема беспокоила меня долгое время.
 Miloš Černilovský10 июн. 2016 г., 09:30
В Android 6 мои бэкэнд-запросы выполнялись намного быстрее, но, к сожалению, эта ошибка все еще существует в Android SDK.
 Chris Eberle17 сент. 2013 г., 22:10
Я искал везде способ сделать это (даже не связанный с Android, просто нужно было отключить обратный поиск DNS в проекте Java). Мне пришлось изменить его для последней JDK - они поставилиhostName один уровень глубже внутриInetAddressHolder класс-обертка (также недоступный, нужно больше размышлений, чтобы обойти это). Еще - спасибо.

Ваш ответ на вопрос