it-swarm.com.de

Deaktivieren von SSLv3 in Android für HttpsUrlConnection

Wir haben eine Client-Anwendung in Android geschrieben, die mit https-Servern über HttpsUrlConnection apis verbunden wird. Aufgrund der Poodle-Sicherheitsanfälligkeit müssen wir SSLv3 aus der Liste der aktivierten Protokolle deaktivieren, während Sie eine Anforderung aufrufen. 

Wir folgten den von Oracle erfassten Richtlinien als http://www.Oracle.com/technetwork/Java/javase/documentation/cve-2014-3566-2342133.html

und vor dem Aufrufen der URL-Verbindung die folgende Zeile hinzugefügt

Java.lang.System.setProperty("https.protocols", "TLSv1");

Diese Lösung funktioniert gut mit normalen Java-Programmen. Wir haben SSLHandShakeException erhalten, als versucht wurde, sich mit einem Server zu verbinden, der nur mit dem SSLv3-Protokoll arbeitet.

Aber Sorge ist: Dieselbe Korrektur funktioniert nicht für Android. Fehlt mir etwas oder sollte ich einen anderen Ansatz für Android ausprobieren? Bitte vorschlagen.

14
user1375399

Ich habe die Lösung dafür gefunden, indem ich die Datenpakete mit Wireshark analysierte. Ich fand heraus, dass Android beim Herstellen einer sicheren Verbindung von TLSv1 auf SSLv3 zurückfiel. Es ist ein Fehler in Android-Versionen <4.4 und kann behoben werden, indem das SSLv3-Protokoll aus der Liste der aktivierten Protokolle entfernt wird. Ich habe eine benutzerdefinierte socketFactory-Klasse namens NoSSLv3SocketFactory.Java erstellt. Verwenden Sie dies, um eine Steckdose herzustellen.

/*Copyright 2015 Bhavit Singh Sengar
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.You may obtain a copy of the License at

http://www.Apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.*/

import Java.io.IOException;
import Java.io.InputStream;
import Java.io.OutputStream;
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.SSLSession;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;


public class NoSSLv3SocketFactory extends SSLSocketFactory{
    private final SSLSocketFactory delegate;

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

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

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

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

private 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));
}

private class NoSSLv3SSLSocket extends DelegateSSLSocket {

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

    }

    @Override
    public void setEnabledProtocols(String[] protocols) {
        if (protocols != null && protocols.length == 1 && "SSLv3".equals(protocols[0])) {

            List<String> enabledProtocols = new ArrayList<String>(Arrays.asList(delegate.getEnabledProtocols()));
            if (enabledProtocols.size() > 1) {
                enabledProtocols.remove("SSLv3");
                System.out.println("Removed SSLv3 from enabled protocols");
            } else {
                System.out.println("SSL stuck with protocol available for " + String.valueOf(enabledProtocols));
            }
            protocols = enabledProtocols.toArray(new String[enabledProtocols.size()]);
        }

        super.setEnabledProtocols(protocols);
    }
}

public 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 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);
    }
}
}

Verwenden Sie diese Klasse wie folgt, wenn Sie eine Verbindung herstellen:

SSLContext sslcontext = SSLContext.getInstance("TLSv1");

            sslcontext.init(null,
                    null,
                    null);
            SSLSocketFactory NoSSLv3Factory = new NoSSLv3SocketFactory(sslcontext.getSocketFactory());

            HttpsURLConnection.setDefaultSSLSocketFactory(NoSSLv3Factory);
            l_connection = (HttpsURLConnection) l_url.openConnection();
            l_connection.connect();

UPDATE:

Die richtige Lösung wäre nun die Installation eines neueren Sicherheitsanbieters mit Google Play Services :

    ProviderInstaller.installIfNeeded(getApplicationContext());

Dadurch kann Ihre App effektiv auf eine neuere Version von OpenSSL und Java Security Provider zugreifen, die TLSv1.2 in SSLEngine unterstützt. Sobald der neue Provider installiert ist, können Sie eine SSLE-Engine erstellen, die SSLv3, TLSv1, TLSv1.1 und TLSv1.2 wie üblich unterstützt: 

    SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
    sslContext.init(null, null, null);
    SSLEngine engine = sslContext.createSSLEngine();

Oder Sie können die aktivierten Protokolle mit engine.setEnabledProtocols einschränken.

Vergessen Sie nicht, die folgende Abhängigkeit ( neueste Version hier ) hinzuzufügen:

compile 'com.google.Android.gms:play-services-auth:11.8.0'

Weitere Informationen erhalten Sie unter link .

36

Inspiriert von Bhavit S. Sengars answer , bündelte es diese Technik zu einem toten einfachen Methodenaufruf. Sie können die Bibliothek " NetCipher " verwenden, um eine moderne TLS-Konfiguration zu erhalten, wenn Sie HttpsURLConnection von Android verwenden. NetCipher konfiguriert die HttpsURLConnection-Instanz für die Verwendung der am besten unterstützten TLS-Version, entfernt die SSLv3-Unterstützung und konfiguriert die besten Chiffresätze für diese TLS-Version. Zuerst fügen Sie es Ihrem build.gradle hinzu:

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

Oder Sie können netcipher-1.2.jar herunterladen und direkt in Ihre App einbinden. Dann statt anrufen:

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

Nennen Sie das:

HttpsURLConnection connection = NetCipher.getHttpsURLConnection(sourceUrl);

Zuerst versuchte ich Bhavit S. Sengars answer und es funktionierte in den meisten Fällen. Aber manchmal gab es auch Probleme, wenn das SSLv3-Protokoll von den aktivierten Protokollen auf einem Android 4.4.4-Gerät entfernt wurde. Die NetCipher - Bibliothek von Hans-Christoph Steiner ist also perfekt, um dieses Problem zu lösen, soweit ich es testen konnte.

Wir verwenden jsoup, um auf verschiedenen Servern eine Menge Web Scraping zu erstellen. Daher können wir HttpsURLConnection connection = NetCipher.getHttpsURLConnection(sourceUrl); nicht festlegen. Ich gehe davon aus, dass das gleiche Problem ist, wenn Sie OkHttp verwenden. 

Die beste Lösung, zu der wir gekommen sind, besteht darin, den info.guardianproject.netcipher.client.TlsOnlySocketFactory von NetCipher als DefaultSSLSocketFactory in einem statischen Block festzulegen. Es ist also für die gesamte Laufzeit unserer App eingestellt:

SSLContext sslcontext = SSLContext.getInstance("TLSv1");
sslcontext.init(null, null, null);
SSLSocketFactory noSSLv3Factory = new TlsOnlySocketFactory(sc.getSocketFactory());
HttpsURLConnection.setDefaultSSLSocketFactory(noSSLv3Factory);

Wenn Sie alle Details überprüfen möchten (mit trustAllCertificates), können Sie dies hier tun.

6
jonastheis

verwenden Sie dieses Code-Snippet. Wenn der Server für SSLv3 aktiviert ist, schlägt das Handshaking fehl. 

        SocketFactory sf = SSLSocketFactory.getDefault();
        SSLSocket socket = (SSLSocket) sf.createSocket("Host-name", 443);
        socket.setEnabledProtocols(new String[] { "TLSv1"});
        socket.startHandshake();
4
Amit Rathore

Stellt eine Verbindung zum https-Server her, benötigen wir ein Zertifikat beim Handshaking von der Clientseite. Vor einem Jahr habe ich ein ähnliches Problem mit dem Selbstzeichen-Zertifikat auf folgende Weise gelöst:

import Java.security.KeyManagementException;
import Java.security.NoSuchAlgorithmException;
import Java.security.SecureRandom;
import Java.security.cert.X509Certificate;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

public class HttpsTrustManager implements X509TrustManager {

private static TrustManager[] trustManagers;
private static final X509Certificate[] _AcceptedIssuers = new X509Certificate[]{};

@Override
public void checkClientTrusted(
        Java.security.cert.X509Certificate[] x509Certificates, String s)
        throws Java.security.cert.CertificateException {

}

@Override
public void checkServerTrusted(
        Java.security.cert.X509Certificate[] x509Certificates, String s)
        throws Java.security.cert.CertificateException {

}

public boolean isClientTrusted(X509Certificate[] chain) {
    return true;
}

public boolean isServerTrusted(X509Certificate[] chain) {
    return true;
}

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

public static void allowAllSSL() {
    HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {

        @Override
        public boolean verify(String arg0, SSLSession arg1) {
            return true;
        }

    });

    SSLContext context = null;
    if (trustManagers == null) {
        trustManagers = new TrustManager[]{new HttpsTrustManager()};
    }

    try {
        context = SSLContext.getInstance("TLS");
        context.init(null, trustManagers, new SecureRandom());
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    } catch (KeyManagementException e) {
        e.printStackTrace();
    }

    HttpsURLConnection.setDefaultSSLSocketFactory(context
            .getSocketFactory());
}

}

Verwendung auf Clientseite vor HttpsUrlConnection

HttpsTrustManager.allowAllSSL();

hoffentlich klappt es :)

1

Eigentlich brauchen wir SSLV3 oder TLSV1.0 nicht zu deaktivieren. Was wir nur brauchen, um TLSV1.1 oder TLSv1.2 in Android <5-Geräten zu aktivieren.

Das Problem ist, dass TLSv1.1 und TLSv1.2 nicht standardmäßig auf Android <5 aktiviert sind. Um eine Verbindung mit diesem neuesten sicheren Protokoll herzustellen, müssen wir es in Android <5-Geräten aktivieren.

Diese Lösung hat mein Problem behoben: https://stackoverflow.com/a/45853669/3448003

0
Bajrang Hudda
 SSLContext sslContext = SSLContext.getInstance("TLSv1");
                sslContext.init(null, null, null);
                SSLSocketFactory socketFactory = sslContext.getSocketFactory();
                            httpURLConnection.setSSLSocketFactory(socketFactory);

HttpsURLConnection mit TSL erstellen eine Sicherheit fehlgeschlagen, die Android-Implementierung wird auf SSLV3 zurückgreifen, um die Verbindung herzustellen.

Bitte beziehen Sie sich auf diese http://code.google.com/p/Android/issues/detail?id=78431

0
kamal_tech_view

Verwendung von PlayService-Publisher-Client-Bibliotheken unter Android Ich habe das gleiche Problem beim Ausführen von sample

Behebung des Problems mit @ bhavit-s-sengars Ahnung oben. Musste AndroidPublisherHelper.newTrustedTransport() auch so ändern:

SSLContext sslcontext = SSLContext.getInstance("TLSv1");
sslcontext.init(null, null, null);
//  NoSSLv3SocketFactory is @bhavit-s-sengar's http://stackoverflow.com/a/29946540/8524
SSLSocketFactory noSSLv3Factory = new NoSSLv3SocketFactory(sslcontext.getSocketFactory());

NetHttpTransport.Builder netTransportBuilder = new NetHttpTransport.Builder();
netTransportBuilder.setSslSocketFactory(noSSLv3Factory);
HTTP_TRANSPORT = netTransportBuilder.build();
0
Diederik