Отключить SSL как протокол в HttpsURLConnection

Из-за уязвимости POODLE мой сервер, размещенный в Amazon AWS, больше не поддерживает SSLv3.

В результате первое HTTPS-соединение, которое мое приложение Android устанавливает с сервером, приводит к ошибке при установке соединения.

Error reading server response: javax.net.ssl.SSLHandshakeException: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0x77d8ab68: Failure in SSL library, usually a protocol error
error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure (external/openssl/ssl/s23_clnt.c:741 0x7339ad74:0x00000000)
       [....]
Caused by: javax.net.ssl.SSLHandshakeException: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0x77d8ab68: Failure in SSL library, usually a protocol error
error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure (external/openssl/ssl/s23_clnt.c:741 0x7339ad74:0x00000000)
       at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:448)
       at com.android.okhttp.Connection.upgradeToTls(Connection.java:146)
       at com.android.okhttp.Connection.connect(Connection.java:107)
       at com.android.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:294)
       at com.android.okhttp.internal.http.HttpEngine.sendSocketRequest(HttpEngine.java:255)
       at com.android.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:206)

Ошибка возникает только в первом запросе. Последующие запросы работают некоторое время.

Чтобы исправить это, я пытаюсь удалить SSL из списка протоколов, принимаемых клиентом Android, и убедиться, что я использую только TLS. Для этого я установил собственный SSLSocketFactory, который удаляет SSL из списка включенных протоколов и поддерживаемых наборов шифрования.

/**
 * SSLSocketFactory that wraps one existing SSLSocketFactory and delegetes into it adding
 * a new cipher suite
 */
public class TLSOnlySocketFactory extends SSLSocketFactory {

    private final SSLSocketFactory delegate;

    public TLSOnlySocketFactory(SSLSocketFactory delegate) {
        this.delegate = delegate;
    }

    @Override
    public String[] getDefaultCipherSuites() {

        return getPreferredDefaultCipherSuites(this.delegate);
    }

    @Override
    public String[] getSupportedCipherSuites() {
        return getPreferredSupportedCipherSuites(this.delegate);
    }



    @Override
    public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
        final Socket socket = this.delegate.createSocket(s, host, port, autoClose);

        ((SSLSocket)socket).setEnabledCipherSuites(getPreferredDefaultCipherSuites(delegate));
        ((SSLSocket)socket).setEnabledProtocols(getEnabledProtocols((SSLSocket)socket));

        return socket;
    }



   [.....]

        ((SSLSocket)socket).setEnabledCipherSuites(getPreferredDefaultCipherSuites(delegate));
        ((SSLSocket) socket).setEnabledProtocols(getEnabledProtocols((SSLSocket)socket));

        return socket;
    }

    @Override
    public Socket createSocket(InetAddress host, int port) throws IOException {
        final Socket socket = this.delegate.createSocket(host, port);

        ((SSLSocket)socket).setEnabledCipherSuites(getPreferredDefaultCipherSuites(delegate));
        ((SSLSocket) socket).setEnabledProtocols(getEnabledProtocols((SSLSocket)socket));

        return socket;
    }

    @Override
    public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
        final Socket socket = this.delegate.createSocket(address, port, localAddress, localPort);

        ((SSLSocket)socket).setEnabledCipherSuites(getPreferredDefaultCipherSuites(delegate));
        ((SSLSocket) socket).setEnabledProtocols(getEnabledProtocols((SSLSocket)socket));

        return socket;
    }

    private String[] getPreferredDefaultCipherSuites(SSLSocketFactory sslSocketFactory) {
        return getCipherSuites(sslSocketFactory.getDefaultCipherSuites());
    }

    private String[] getPreferredSupportedCipherSuites(SSLSocketFactory sslSocketFactory) {
        return getCipherSuites(sslSocketFactory.getSupportedCipherSuites());
    }

    private String[] getCipherSuites(String[] cipherSuites) {
        final ArrayList<String> suitesList = new ArrayList<String>(Arrays.asList(cipherSuites));
        final Iterator<String> iterator = suitesList.iterator();
        while (iterator.hasNext()) {
            final String cipherSuite = iterator.next();
            if (cipherSuite.contains("SSL")) {
                iterator.remove();
            }
        }
        return suitesList.toArray(new String[suitesList.size()]);
    }

    private String[] getEnabledProtocols(SSLSocket socket) {
        final ArrayList<String> protocolList = new ArrayList<String>(Arrays.asList(socket.getSupportedProtocols()));
        final Iterator<String> iterator = protocolList.iterator();
        while (iterator.hasNext()) {
            final String protocl = iterator.next();
            if (protocl.contains("SSL")) {
                iterator.remove();
            }
        }
        return protocolList.toArray(new String[protocolList.size()]);
     }

}

Как видите, моя SSLSocketFactory делегирует другую SSLSocketFactory и просто удаляет SSL из списка включенных протоколов.

Я основываю эту фабрику как

final TLSOnlySocketFactory tlsOnlySocketFactory = new TLSOnlySocketFactory(HttpsURLConnection.getDefaultSSLSocketFactory());
HttpsURLConnection.setDefaultSSLSocketFactory(tlsOnlySocketFactory);

Это НЕ решает проблему. Время от времени я все еще вижу ошибку, когда соединение было установлено. Как ни странно, это не решает проблему, но явно сводит к минимуму возникновение проблемы.

Как я могу заставить HttpsUrlConnection в моем Android-клиенте использовать только TLS?

Спасибо.


person GaRRaPeTa    schedule 29.10.2014    source источник
comment
Вы решаете не ту проблему. Тебе не нужно этого делать. Ваша проблема в другом.   -  person user207421    schedule 29.10.2014
comment
Если это неправильный способ, как мне убедиться, что мой HttpsUrlConnection использует только TLS?   -  person GaRRaPeTa    schedule 03.11.2014
comment
Привет, я тоже застрял в этой проблеме. Вы нашли способ решить эту проблему? Мне тоже нужно решить эту проблему глобально, потому что я использую некоторые банки, которые тоже заражены   -  person edoardotognoni    schedule 14.11.2014
comment
@EJP У вас есть идеи, как решить проблему? Если да, дайте нам несколько подсказок: D   -  person edoardotognoni    schedule 14.11.2014
comment
Исправить не удалось. Я застрял. На данный момент я нашел следующие обходные пути: 1. Используйте Apache Http Client вместо HttpURLConnection (что отстой). 2. Используйте HttpURLConnection, и когда я поймаю IOException с SSLHandshakeException в качестве причины, беззвучно повторите запрос (что тоже отстой).   -  person GaRRaPeTa    schedule 14.11.2014
comment
Есть новости об этом от кого-нибудь? Я все еще делаю повторные попытки, и мне бы очень хотелось решить эту проблему ...   -  person GaRRaPeTa    schedule 05.01.2015


Ответы (6)


Думаю, я решил эту проблему. Основная идея та же, что и в коде, о котором идет речь (избегайте SSLv3 как единственного доступного протокола), но код, выполняющий его, отличается:

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.InetAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.SocketException;
import java.nio.channels.SocketChannel;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import javax.net.ssl.HandshakeCompletedListener;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLParameters;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;

    /**
     * {@link javax.net.ssl.SSLSocketFactory} that doesn't allow {@code SSLv3} only connections
     * <p>fixes https://github.com/koush/ion/issues/386</p>
     *
     * <p> see https://code.google.com/p/android/issues/detail?id=78187 </p>
     */
    public class NoSSLv3Factory extends SSLSocketFactory {
        private final SSLSocketFactory delegate;

        public NoSSLv3Factory() {
            this.delegate = HttpsURLConnection.getDefaultSSLSocketFactory();
        }

        @Override
        public String[] getDefaultCipherSuites() {
            return delegate.getDefaultCipherSuites();
        }

        @Override
        public String[] getSupportedCipherSuites() {
            return delegate.getSupportedCipherSuites();
        }

        private static Socket makeSocketSafe(Socket socket) {
            if (socket instanceof SSLSocket) {
                socket = new NoSSLv3SSLSocket((SSLSocket) socket);
            }
            return socket;
        }

        @Override
        public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
            return makeSocketSafe(delegate.createSocket(s, host, port, autoClose));
        }

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

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

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

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

        /**
         * Created by robUx4 on 25/10/2014.
         */
        private static class DelegateSSLSocket extends SSLSocket {

            protected final SSLSocket delegate;

            DelegateSSLSocket(SSLSocket delegate) {
                this.delegate = delegate;
            }

            @Override
            public String[] getSupportedCipherSuites() {
                return delegate.getSupportedCipherSuites();
            }

            @Override
            public String[] getEnabledCipherSuites() {
                return delegate.getEnabledCipherSuites();
            }

            @Override
            public void setEnabledCipherSuites(String[] suites) {
                delegate.setEnabledCipherSuites(suites);
            }

            @Override
            public String[] getSupportedProtocols() {
                return delegate.getSupportedProtocols();
            }

            @Override
            public String[] getEnabledProtocols() {
                return delegate.getEnabledProtocols();
            }

            @Override
            public void setEnabledProtocols(String[] protocols) {
                delegate.setEnabledProtocols(protocols);
            }

            @Override
            public SSLSession getSession() {
                return delegate.getSession();
            }

            @Override
            public void addHandshakeCompletedListener(HandshakeCompletedListener listener) {
                delegate.addHandshakeCompletedListener(listener);
            }

            @Override
            public void removeHandshakeCompletedListener(HandshakeCompletedListener listener) {
                delegate.removeHandshakeCompletedListener(listener);
            }

            @Override
            public void startHandshake() throws IOException {
                delegate.startHandshake();
            }

            @Override
            public void setUseClientMode(boolean mode) {
                delegate.setUseClientMode(mode);
            }

            @Override
            public boolean getUseClientMode() {
                return delegate.getUseClientMode();
            }

            @Override
            public void setNeedClientAuth(boolean need) {
                delegate.setNeedClientAuth(need);
            }

            @Override
            public void setWantClientAuth(boolean want) {
                delegate.setWantClientAuth(want);
            }

            @Override
            public boolean getNeedClientAuth() {
                return delegate.getNeedClientAuth();
            }

            @Override
            public boolean getWantClientAuth() {
                return delegate.getWantClientAuth();
            }

            @Override
            public void setEnableSessionCreation(boolean flag) {
                delegate.setEnableSessionCreation(flag);
            }

            @Override
            public boolean getEnableSessionCreation() {
                return delegate.getEnableSessionCreation();
            }

            @Override
            public void bind(SocketAddress localAddr) throws IOException {
                delegate.bind(localAddr);
            }

            @Override
            public synchronized void close() throws IOException {
                delegate.close();
            }

            @Override
            public void connect(SocketAddress remoteAddr) throws IOException {
                delegate.connect(remoteAddr);
            }

            @Override
            public void connect(SocketAddress remoteAddr, int timeout) throws IOException {
                delegate.connect(remoteAddr, timeout);
            }

            @Override
            public SocketChannel getChannel() {
                return delegate.getChannel();
            }

            @Override
            public InetAddress getInetAddress() {
                return delegate.getInetAddress();
            }

            @Override
            public InputStream getInputStream() throws IOException {
                return delegate.getInputStream();
            }

            @Override
            public boolean getKeepAlive() throws SocketException {
                return delegate.getKeepAlive();
            }

            @Override
            public InetAddress getLocalAddress() {
                return delegate.getLocalAddress();
            }

            @Override
            public int getLocalPort() {
                return delegate.getLocalPort();
            }

            @Override
            public SocketAddress getLocalSocketAddress() {
                return delegate.getLocalSocketAddress();
            }

            @Override
            public boolean getOOBInline() throws SocketException {
                return delegate.getOOBInline();
            }

            @Override
            public OutputStream getOutputStream() throws IOException {
                return delegate.getOutputStream();
            }

            @Override
            public int getPort() {
                return delegate.getPort();
            }

            @Override
            public synchronized int getReceiveBufferSize() throws SocketException {
                return delegate.getReceiveBufferSize();
            }

            @Override
            public SocketAddress getRemoteSocketAddress() {
                return delegate.getRemoteSocketAddress();
            }

            @Override
            public boolean getReuseAddress() throws SocketException {
                return delegate.getReuseAddress();
            }

            @Override
            public synchronized int getSendBufferSize() throws SocketException {
                return delegate.getSendBufferSize();
            }

            @Override
            public int getSoLinger() throws SocketException {
                return delegate.getSoLinger();
            }

            @Override
            public synchronized int getSoTimeout() throws SocketException {
                return delegate.getSoTimeout();
            }

            @Override
            public boolean getTcpNoDelay() throws SocketException {
                return delegate.getTcpNoDelay();
            }

            @Override
            public int getTrafficClass() throws SocketException {
                return delegate.getTrafficClass();
            }

            @Override
            public boolean isBound() {
                return delegate.isBound();
            }

            @Override
            public boolean isClosed() {
                return delegate.isClosed();
            }

            @Override
            public boolean isConnected() {
                return delegate.isConnected();
            }

            @Override
            public boolean isInputShutdown() {
                return delegate.isInputShutdown();
            }

            @Override
            public boolean isOutputShutdown() {
                return delegate.isOutputShutdown();
            }

            @Override
            public void sendUrgentData(int value) throws IOException {
                delegate.sendUrgentData(value);
            }

            @Override
            public void setKeepAlive(boolean keepAlive) throws SocketException {
                delegate.setKeepAlive(keepAlive);
            }

            @Override
            public void setOOBInline(boolean oobinline) throws SocketException {
                delegate.setOOBInline(oobinline);
            }

            @Override
            public void setPerformancePreferences(int connectionTime, int latency, int bandwidth) {
                delegate.setPerformancePreferences(connectionTime, latency, bandwidth);
            }

            @Override
            public synchronized void setReceiveBufferSize(int size) throws SocketException {
                delegate.setReceiveBufferSize(size);
            }

            @Override
            public void setReuseAddress(boolean reuse) throws SocketException {
                delegate.setReuseAddress(reuse);
            }

            @Override
            public synchronized void setSendBufferSize(int size) throws SocketException {
                delegate.setSendBufferSize(size);
            }

            @Override
            public void setSoLinger(boolean on, int timeout) throws SocketException {
                delegate.setSoLinger(on, timeout);
            }

            @Override
            public synchronized void setSoTimeout(int timeout) throws SocketException {
                delegate.setSoTimeout(timeout);
            }

            @Override
            public void setSSLParameters(SSLParameters p) {
                delegate.setSSLParameters(p);
            }

            @Override
            public void setTcpNoDelay(boolean on) throws SocketException {
                delegate.setTcpNoDelay(on);
            }

            @Override
            public void setTrafficClass(int value) throws SocketException {
                delegate.setTrafficClass(value);
            }

            @Override
            public void shutdownInput() throws IOException {
                delegate.shutdownInput();
            }

            @Override
            public void shutdownOutput() throws IOException {
                delegate.shutdownOutput();
            }

            @Override
            public String toString() {
                return delegate.toString();
            }

            @Override
            public boolean equals(Object o) {
                return delegate.equals(o);
            }
        }

        /**
         * An {@link javax.net.ssl.SSLSocket} that doesn't allow {@code SSLv3} only connections
         * <p>fixes https://github.com/koush/ion/issues/386</p>
         */
        private static class NoSSLv3SSLSocket extends DelegateSSLSocket {

            private NoSSLv3SSLSocket(SSLSocket delegate) {
                super(delegate);

                String canonicalName = delegate.getClass().getCanonicalName();
                if (!canonicalName.equals("org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl")) {
                    // try replicate the code from HttpConnection.setupSecureSocket()
                    try {
                        Method msetUseSessionTickets = delegate.getClass().getMethod("setUseSessionTickets", boolean.class);
                        if (null != msetUseSessionTickets) {
                            msetUseSessionTickets.invoke(delegate, true);
                        }
                    } catch (NoSuchMethodException ignored) {
                    } catch (InvocationTargetException ignored) {
                    } catch (IllegalAccessException ignored) {
                    }
                }
            }

            @Override
            public void setEnabledProtocols(String[] protocols) {
                if (protocols != null && protocols.length == 1 && "SSLv3".equals(protocols[0])) {
                    // no way jose
                    // see issue https://code.google.com/p/android/issues/detail?id=78187
                    List<String> enabledProtocols = new ArrayList<String>(Arrays.asList(delegate.getEnabledProtocols()));
                    if (enabledProtocols.size() > 1) {
                        enabledProtocols.remove("SSLv3");
                    }
                    protocols = enabledProtocols.toArray(new String[enabledProtocols.size()]);
                }
                super.setEnabledProtocols(protocols);
            }
        }

    }

и где-то в вашем коде перед созданием соединения:

    static {
    HttpsURLConnection.setDefaultSSLSocketFactory(new NoSSLv3Factory());
}

Этот код взят из https://code.google.com/p/android/issues/detail?id=78187, где вы можете найти полное объяснение того, почему это происходит в Android 4.X.

Я производил это в течение одной недели и, похоже, добился цели.

person GaRRaPeTa    schedule 13.01.2015
comment
привет, это исправление у меня работает, но я запустил мое приложение с фиксированным кодом один раз, а старая версия была удалена и установлена ​​- ›теперь старая версия все еще работает .... кэширует ли система Android где-нибудь эту настройку? могу я его удалить? перезагрузка тоже не помогла - person wutzebaer; 28.05.2015
comment
@GaRRaPeTa Я использовал клиент NoSSLv3Factory, но он не работает на устройстве Samsung S3. При загрузке URL-адреса в приложении WebView выдается сообщение об ошибке Веб-страница не найдена. Это проблема конкретного устройства? Если нет, дайте мне знать, если нам нужно изменить настройки веб-просмотра. - person KK_07k11A0585; 03.08.2015
comment
Я никогда не сталкивался с этой проблемой. Изменение фабрики SSL нацелено на тот случай, когда вы используете HttpUrlConnection для подключения к вашему серверу - фабрика создаст объекты HttpUrlConnection, которые не будут использовать устаревший протокол SSLLv3. Однако я не знаю, сработает ли это для веб-просмотра. Я не знаю, какой HTTP-клиент использует webview под капотом. - person GaRRaPeTa; 03.08.2015
comment
В любом случае, если ваш веб-просмотр говорит, что веб-страница не найдена, я думаю, что это не имеет никакого отношения к этому, это просто 404, а не проблема с подключением, вызванная проблемами рукопожатия из-за несовместимых наборов шифров. - person GaRRaPeTa; 03.08.2015
comment
@GaRRaPeTa Я пытаюсь загрузить URL-адрес в веб-просмотре вместо того, чтобы подключаться к нему с помощью HttpUrlConnection. Итак, как я могу удалить протокол SSLV3 из настроек веб-просмотра при загрузке URL-адреса? - person KK_07k11A0585; 04.08.2015
comment
Я все еще испытываю SSLHandshakeException. Я использую okHTTP с Retrofit. Используя этот класс так: okClient.setSslSocketFactory(new NoSSLv3Factory());. Это работает с okHTTP и Retrofit? - person Sakiboy; 04.02.2016
comment
Как мы можем сохранить код в статическом блоке без идентификатора или типа static {HttpsURLConnection.setDefaultSSLSocketFactory (new NoSSLv3Factory ()); } - person SriMaharshi Manchem; 15.04.2016
comment
Используя это с модернизацией, httpClient.socketFactory (new NoSSLv3Factory ()); У меня новая ошибка SocketException: неподключенные сокеты не реализованы - person niczm25; 08.08.2017

Я взял ответ от @ GaRRaPeTa и объединил его в мертвый простой вызов метода. Вы можете использовать библиотеку NetCipher для получения современной конфигурации TLS при использовании HttpsURLConnection Android. NetCipher настраивает экземпляр HttpsURLConnection для использования наилучшей поддерживаемой версии TLS, удаляет поддержку SSLv3 и настраивает лучший набор шифров для этой версии TLS. Сначала добавьте его в свой build.gradle:

compile 'info.guardianproject.netcipher:netcipher:1.2'

Или вы можете загрузить netcipher-1.2.jar и включить его прямо в свое приложение. Тогда вместо звонка:

HttpURLConnection connection = (HttpURLConnection) sourceUrl.openConnection();

Назовите это:

HttpsURLConnection connection = NetCipher.getHttpsURLConnection(sourceUrl);
person Hans-Christoph Steiner    schedule 08.09.2015
comment
Пробовал на эмуляторе Android 4.0, получил javax.net.ssl.SSLException: соединение закрыто одноранговым узлом - person broderix; 18.11.2015
comment
Это обеспечивает хорошие конфигурации SSL, поэтому, если вы подключаетесь к серверу, который, например, поддерживает только SSLv3, вы получите исключение. Или если этот сервер поддерживает только слабые шифры или имеет проблемы с включенным TLSv1.2. - person Hans-Christoph Steiner; 16.12.2015
comment
Единственное решение, которое сработало для меня. Спасибо, @ Hans-ChristophSteiner - person user3105453; 13.05.2016
comment
Получение подпрограмм SSL: SSL23_GET_SERVER_HELLO: сбой подтверждения sslv3 при вызове conn.getOutputStream () на устройстве Android 2.2 - person QuantumTiger; 05.09.2016
comment
В ходе расследования кажется, что указанное выше решение работает только с API 9 и выше. Android 2.2 - это API 8: / - person QuantumTiger; 07.09.2016
comment
У меня работал с OKHttp, Retrofit. - person patric_cena; 23.09.2016

Вышеупомянутые решения не сработали для меня, поэтому я узнал и сделал это, чтобы преодолеть эту проблему.

Для более старых устройств, чем Android 5.0, поставщик безопасности по умолчанию имел следующие свойства:

  1. Протоколы TSLv1 и TSLv2 не были включены по умолчанию
  2. Протокол SSLv3 по умолчанию не отключен.

Решение, которое сработало для меня, состоит в том, чтобы при необходимости исправить «Поставщика» при запуске приложения, чтобы в его списке протоколов больше не было SSLv3. Простой способ исправить Android из вашего приложения: (учитывая, что у вас есть доступ к сервисам Google Play Store).

private void updateAndroidSecurityProvider(Activity callingActivity) {
    try {
        ProviderInstaller.installIfNeeded(this);
    } catch (GooglePlayServicesRepairableException e) {
        // Thrown when Google Play Services is not installed, up-to-date, or enabled
        // Show dialog to allow users to install, update, or otherwise enable Google Play services.
        GooglePlayServicesUtil.getErrorDialog(e.getConnectionStatusCode(), callingActivity, 0);
    } catch (GooglePlayServicesNotAvailableException e) {
        Log.e("SecurityException", "Google Play Services not available.");
    }
}

Взгляните на: https://developer.android.com/training/articles/security-gms-provider.html?#patching для получения дополнительной информации.

person Meriton Husaj    schedule 03.12.2016

Помимо ответа @ GaRRaPeTa, убедитесь, что метод makeSocketsafe определяет, не преобразован ли сокет в NoSSLv3SSLSocket, чтобы предотвратить проблемы с Stackoverflow:

    private static Socket makeSocketSafe(Socket socket) {
        if (socket instanceof SSLSocket && !(socket instanceof NoSSLv3SSLSocket)) {
            socket = new NoSSLv3SSLSocket((SSLSocket) socket);
        }
        return socket;
    }

PS. Не могу комментировать, поэтому это отдельный пост.

person Pier Betos    schedule 20.02.2015
comment
привет, у меня все еще возникают ошибки переполнения стека, потому что я вызвал HttpsURLConnection.setDefaultSSLSocketFactory (new NoSSLv3Factory ()); несколько раз, и стек делегата становился все длиннее и длиннее, я исправил это, сделав статическую переменную: private static final SSLSocketFactory delegate = HttpsURLConnection.getDefaultSSLSocketFactory (); - person wutzebaer; 18.12.2015

Я недавно протестировал это с помощью SSLContext (так как мне нужен был доступ к Trustmanager) вместо реализации моего собственного NoSSLv3Factory, и пока у меня не было никаких проблем.

private getSSLContext()
{
    /* Load the keyStore that includes self-signed cert as a "trusted" entry. */
    KeyStore keyStore = ...  //optional
    TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); //optional
    tmf.init(keyStore); //optional

    //This is the important line, specifying the cipher to use and cipher provider
    SSLContext sslContext = SSLContext.getInstance("TLSv1","AndroidOpenSSL");
    ctx.init(null, tmf.getTrustManagers(), null); //if trustmanager not used pass null as the second parameter    
    return sslContext;
}

Затем вы можете использовать это в своем объекте HttpsURLConnection следующим образом:

...
URL url = new URL("https://yourwebapp.com/");
HttpsURLConnection webConnection = (HttpsURLConnection)url.openConnection();
webConnection.setSSLSocketFactory(getSSLContext())
...    

Это означает, что вам придется постоянно следить за любыми уязвимостями TLS и изменять указанный шифр, если какие-либо уязвимости SSL / TLS будут публично раскрыты.

Список поддерживаемых шифров и поставщиков, которые вы можете использовать перечислены здесь

Первый блок кода, незначительное ключевое изменение для этого сценария, в основном был взят из этого SO-ответа

person skyjacks    schedule 12.08.2015

Также вы должны знать, что вы можете принудительно использовать TLS v1.2 для устройств Android 4.0, на которых он не включен по умолчанию:

Это должно быть в первой строке вашего приложения:

 try {
            ProviderInstaller.installIfNeeded(getApplicationContext());
            SSLContext sslContext;
            sslContext = SSLContext.getInstance("TLSv1.2");
            sslContext.init(null, null, null);
            sslContext.createSSLEngine();
        } catch (GooglePlayServicesRepairableException | GooglePlayServicesNotAvailableException
                | NoSuchAlgorithmException | KeyManagementException e) {
            e.printStackTrace();
        }
person Mayur Gangurde    schedule 11.07.2018