Ich versuche, den folgenden Code in Android auszuführen
URLConnection l_connection = null;
// Create connection
uzip=new UnZipData(mContext);
l_url = new URL(serverurl);
if ("https".equals(l_url.getProtocol())) {
System.out.println("<<<<<<<<<<<<< Before TLS >>>>>>>>>>>>");
sslcontext = SSLContext.getInstance("TLS");
System.out.println("<<<<<<<<<<<<< After TLS >>>>>>>>>>>>");
sslcontext.init(null,
new TrustManager[] { new CustomTrustManager()},
new Java.security.SecureRandom());
HttpsURLConnection
.setDefaultHostnameVerifier(new CustomHostnameVerifier());
HttpsURLConnection.setDefaultSSLSocketFactory(sslcontext
.getSocketFactory());
l_connection = (HttpsURLConnection) l_url.openConnection();
((HttpsURLConnection) l_connection).setRequestMethod("POST");
} else {
l_connection = (HttpURLConnection) l_url.openConnection();
((HttpURLConnection) l_connection).setRequestMethod("POST");
}
/*System.setProperty("http.agent", "Android_Phone");*/
l_connection.setConnectTimeout(10000);
l_connection.setRequestProperty("Content-Language", "en-US");
l_connection.setUseCaches(false);
l_connection.setDoInput(true);
l_connection.setDoOutput(true);
System.out.println("<<<<<<<<<<<<< Before Connection >>>>>>>>>>>>");
l_connection.connect();
Bei l_connection.connect()
gibt es diese SSLhandshakeException. Manchmal funktioniert es, aber die meiste Zeit gibt es eine Ausnahme. Dies geschieht nur unter Android 4.0-Emulator. Ich habe es auf Android 4.4 und 5.0 getestet, es funktioniert gut. Was könnte die Ursache sein? Bitte helfen
STACKTRACE
04-28 15:51:13.143: W/System.err(2915): javax.net.ssl.SSLHandshakeException: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0x870c918: Failure in SSL library, usually a protocol error
04-28 15:51:13.143: W/System.err(2915): error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure (external/openssl/ssl/s23_clnt.c:658 0xb7c393a1:0x00000000)
04-28 15:51:13.143: W/System.err(2915): at org.Apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.Java:460)
04-28 15:51:13.143: W/System.err(2915): at org.Apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.Java:257)
04-28 15:51:13.143: W/System.err(2915): at libcore.net.http.HttpConnection.setupSecureSocket(HttpConnection.Java:210)
04-28 15:51:13.143: W/System.err(2915): at libcore.net.http.HttpsURLConnectionImpl$HttpsEngine.makeSslConnection(HttpsURLConnectionImpl.Java:477)
04-28 15:51:13.153: W/System.err(2915): at libcore.net.http.HttpsURLConnectionImpl$HttpsEngine.connect(HttpsURLConnectionImpl.Java:441)
04-28 15:51:13.153: W/System.err(2915): at libcore.net.http.HttpEngine.sendSocketRequest(HttpEngine.Java:282)
04-28 15:51:13.153: W/System.err(2915): at libcore.net.http.HttpEngine.sendRequest(HttpEngine.Java:232)
04-28 15:51:13.153: W/System.err(2915): at libcore.net.http.HttpURLConnectionImpl.connect(HttpURLConnectionImpl.Java:80)
04-28 15:51:13.153: W/System.err(2915): at libcore.net.http.HttpsURLConnectionImpl.connect(HttpsURLConnectionImpl.Java:164)
04-28 15:51:13.153: W/System.err(2915): at com.ofss.fcdb.mobile.Android.rms.helpers.NetworkConnector.getConnection(NetworkConnector.Java:170)
04-28 15:51:13.153: W/System.err(2915): at com.ofss.fcdb.mobile.Android.rms.util.InitiateRMS$2.run(InitiateRMS.Java:221)
04-28 15:51:13.153: W/System.err(2915): at Java.lang.Thread.run(Thread.Java:856)
04-28 15:51:13.153: W/System.err(2915): Caused by: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0x870c918: Failure in SSL library, usually a protocol error
04-28 15:51:13.153: W/System.err(2915): error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure (external/openssl/ssl/s23_clnt.c:658 0xb7c393a1:0x00000000)
04-28 15:51:13.153: W/System.err(2915): at org.Apache.harmony.xnet.provider.jsse.NativeCrypto.SSL_do_handshake(Native Method)
04-28 15:51:13.153: W/System.err(2915): at org.Apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.Java:410)
04-28 15:51:13.153: W/System.err(2915): ... 11 more
04-28 16:42:44.139: W/ResourceType(3140): No package identifier when getting value for resource number 0x00000000
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 .
Szenario
Ich habe SSLHandshake-Ausnahmen auf Geräten erhalten, auf denen Android-Versionen vor Android 5.0 ausgeführt werden. In meinem Anwendungsfall wollte ich auch einen TrustManager erstellen, der meinem Client-Zertifikat vertraut.
Ich habe NoSSLv3SocketFactory und NoSSLv3Factory implementiert, um SSLv3 aus der Liste der unterstützten Protokolle meines Clients zu entfernen, aber ich konnte keine dieser Lösungen zum Laufen bringen.
Einige Dinge, die ich gelernt habe:
Was für mich funktionierte
Lassen Sie die Sicherheit der Android-Variable Provider
zu, wenn Sie Ihre App starten.
Der Standardanbieter vor 5.0+ deaktiviert SSLv3 nicht. Sofern Sie Zugriff auf Google Play-Dienste haben, ist es relativ einfach, den Android-Sicherheitsanbieter von Ihrer App zu patchen.
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.");
}
}
Wenn Sie jetzt Ihren OkHttpClient oder Ihre HttpURLConnection erstellen, sollten TLSv1.1 und TLSv1.2 als Protokolle verfügbar sein und SSLv3 sollte entfernt werden. Wenn der Client/die Verbindung (oder genauer SSLContext) vor dem Aufruf von ProviderInstaller.installIfNeeded(...)
initialisiert wurde, muss sie neu erstellt werden.
Vergessen Sie nicht, die folgende Abhängigkeit ( neueste Version hier ) hinzuzufügen:
compile 'com.google.Android.gms:play-services-auth:16.0.1'
Quellen:
Beiseite
Ich musste nicht explizit festlegen, welche Chiffrieralgorithmen mein Client verwenden soll, aber ich habe einen SO -Posten gefunden, in dem die zum Zeitpunkt des Schreibens als sichersten empfohlen werden: Welche Cipher Suites für SSL Socket aktivieren?
Sie sollten auch wissen, dass Sie TLS v1.2 für Android 4.0-Geräte erzwingen können, für die es standardmäßig nicht aktiviert ist:
Dies sollte in der ersten Zeile Ihrer Bewerbung stehen:
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();
}
Bisher habe ich dieses Problem auch mit einer benutzerdefinierten SSLFactory
-Implementierung gelöst, aber laut OkHttp docs ist die Lösung viel einfacher.
Meine endgültige Lösung mit TLS
-Chiffren für 4.2+ -Geräte sieht folgendermaßen aus:
public UsersApi provideUsersApi() {
private ConnectionSpec spec = new ConnectionSpec.Builder(ConnectionSpec.COMPATIBLE_TLS)
.supportsTlsExtensions(true)
.tlsVersions(TlsVersion.TLS_1_2, TlsVersion.TLS_1_1, TlsVersion.TLS_1_0)
.cipherSuites(
CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
CipherSuite.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,
CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
CipherSuite.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
CipherSuite.TLS_ECDHE_RSA_WITH_RC4_128_SHA,
CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA,
CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA)
.build();
OkHttpClient client = new OkHttpClient.Builder()
.connectionSpecs(Collections.singletonList(spec))
.build();
return new Retrofit.Builder()
.baseUrl(USERS_URL)
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.build()
.create(UsersApi.class);
}
Beachten Sie, dass die unterstützten Protokolle von der Konfiguration auf Ihrem Server abhängig sind.
Das hat es für mich gelöst:
Die Android-Dokumentation für SSLSocket besagt, dass TLS 1.1 und TLS 1.2 ab Android-API-Level 16+ (Android 4.1, Jelly Bean) unterstützt werden. Sie ist jedoch standardmäßig deaktiviert, aber ab API Level 20 (Android 4.4 für Watch, KitKat Watch und Android 5.0 für Telefon, Lollipop) sind sie aktiviert. Es ist jedoch sehr schwierig, eine Dokumentation darüber zu finden, wie diese Funktion für Telefone aktiviert wird, auf denen 4.1 ausgeführt wird, z. B. . Um TLS 1.1 und 1.2 zu aktivieren, müssen Sie eine benutzerdefinierte SSLSocketFactory erstellen, die alle Aufrufe einer standardmäßigen SSLSocketFactory-Implementierung weiterleitet. Außerdem müssen wir alle createSocket-Methoden und CallsetEnabledProtocols auf dem zurückgegebenen SSLSocket überschreiben, um TLS 1.1 und TLS 1.2 zu aktivieren. Für eine Beispielimplementierung folgen Sie einfach dem Link unten.
Es war nur reproduzierbar, wenn ich Proxy für Genymotion verwende (<4.4).
Überprüfen Sie Ihre Proxy-Einstellungen in Einstellungen-> Drahtlos & Netzwerke-> WLAN -> (Langes Drücken auf WiredSSID) -> Netzwerk ändern
Wählen Sie Erweiterte Optionen anzeigen: Setzen Sie die Proxy-Einstellungen auf NONE.
Meine Antwort liegt nahe an den obigen Antworten, aber Sie müssen die Klasse genau schreiben, ohne etwas zu ändern.
public class TLSSocketFactory extends SSLSocketFactory {
private SSLSocketFactory delegate;
public TLSSocketFactory() throws KeyManagementException, NoSuchAlgorithmException {
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, null, null);
delegate = context.getSocketFactory();
}
@Override
public String[] getDefaultCipherSuites() {
return delegate.getDefaultCipherSuites();
}
@Override
public String[] getSupportedCipherSuites() {
return delegate.getSupportedCipherSuites();
}
@Override
public Socket createSocket() throws IOException {
return enableTLSOnSocket(delegate.createSocket());
}
@Override
public Socket createSocket(Socket s, String Host, int port, boolean autoClose) throws IOException {
return enableTLSOnSocket(delegate.createSocket(s, Host, port, autoClose));
}
@Override
public Socket createSocket(String Host, int port) throws IOException, UnknownHostException {
return enableTLSOnSocket(delegate.createSocket(Host, port));
}
@Override
public Socket createSocket(String Host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException {
return enableTLSOnSocket(delegate.createSocket(Host, port, localHost, localPort));
}
@Override
public Socket createSocket(InetAddress Host, int port) throws IOException {
return enableTLSOnSocket(delegate.createSocket(Host, port));
}
@Override
public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
return enableTLSOnSocket(delegate.createSocket(address, port, localAddress, localPort));
}
private Socket enableTLSOnSocket(Socket socket) {
if(socket != null && (socket instanceof SSLSocket)) {
((SSLSocket)socket).setEnabledProtocols(new String[] {"TLSv1.1", "TLSv1.2"});
}
return socket;
}
}
und mit HttpsURLConnection verwenden
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
int sdk = Android.os.Build.VERSION.SDK_INT;
if (sdk < Build.VERSION_CODES.Lollipop) {
if (url.toString().startsWith("https")) {
try {
TLSSocketFactory sc = new TLSSocketFactory();
conn.setSSLSocketFactory(sc);
} catch (Exception e) {
String sss = e.toString();
}
}
}
Ich habe das Problem dadurch gelöst: NoSSLv3SocketFactory.Java
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);
super.setEnabledProtocols(new String[]{"TLSv1.2"});
}
}
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);
}
}
}
Hauptklasse :
URL url = new URL("https://www.example.com/test.png");
URLConnection l_connection = null;
SSLContext sslcontext = SSLContext.getInstance("TLSv1.2");
sslcontext.init(null, null, null);
SSLSocketFactory NoSSLv3Factory = new NoSSLv3SocketFactory(sslcontext.getSocketFactory());
Als ich diesen Fehler erhielt, lag dies daran, dass die vom Server unterstützten Protokolle (TLS-Versionen) und/oder Verschlüsselungssuiten auf dem Gerät nicht aktiviert waren (und möglicherweise auch nicht). Für API 16-19 werden TLSv1.1 und TLSv1.2 unterstützt, jedoch nicht standardmäßig aktiviert. Nachdem ich sie für diese Versionen aktiviert habe, wurde der Fehler immer noch angezeigt, da diese Versionen keine der Verschlüsselungscodes in unserer AWS CloudFront-Instanz unterstützen.
Da es nicht möglich ist, Verschlüsselungen zu Android hinzuzufügen, mussten wir unsere CloudFront-Version von TLSv1.2_2018 auf TLSv1.1_2016 umstellen (die weiterhin TLSv1.2 unterstützt; sie erfordert es einfach nicht) Die früheren Android-Versionen, von denen zwei immer noch als stark gelten.
Zu diesem Zeitpunkt verschwand der Fehler und die Anrufe gingen durch (mit TLSv1.2), da mindestens ein Protokoll und mindestens eine Verschlüsselung vorhanden waren, die das Gerät und der Server gemeinsam verwendeten.
In den Tabellen auf dieser Seite erfahren Sie, welche Protokolle und Verschlüsselungen von welchen Android-Versionen unterstützt und aktiviert sind.
Versuchte Android nun wirklich, SSLv3 zu verwenden, wie dies durch den "sslv3 alert Handshake failure" Teil der Fehlermeldung impliziert wird? Ich bezweifle das; Ich vermute, dies ist ein altes Spinnennetz in der SSL-Bibliothek, das noch nicht entfernt wurde, aber ich kann es nicht mit Sicherheit sagen.
Um TLSv1.2 (und TLSv1.1) zu aktivieren, konnte ich eine viel einfachere SSLSocketFactory
als die anderswo verwendeten verwenden (wie NoSSLv3SocketFactory
). Es stellt lediglich sicher, dass die aktivierten Protokolle alle unterstützten Protokolle enthalten und dass die aktivierten Chiffren alle unterstützten Chiffren enthalten (letzteres war für mich nicht notwendig, könnte aber für andere sein) - siehe configure()
unten. Wenn Sie nur die neuesten Protokolle aktivieren möchten, können Sie socket.supportedProtocols
durch etwas wie arrayOf("TLSv1.1", "TLSv1.2")
ersetzen (ebenfalls für die Chiffren):
class TLSSocketFactory : SSLSocketFactory() {
private val socketFactory: SSLSocketFactory
init {
val sslContext = SSLContext.getInstance("TLS")
sslContext.init(null, null, null)
socketFactory = sslContext.socketFactory
}
override fun getDefaultCipherSuites(): Array<String> {
return socketFactory.defaultCipherSuites
}
override fun getSupportedCipherSuites(): Array<String> {
return socketFactory.supportedCipherSuites
}
override fun createSocket(s: Socket, Host: String, port: Int, autoClose: Boolean): Socket {
return configure(socketFactory.createSocket(s, Host, port, autoClose) as SSLSocket)
}
override fun createSocket(Host: String, port: Int): Socket {
return configure(socketFactory.createSocket(Host, port) as SSLSocket)
}
override fun createSocket(Host: InetAddress, port: Int): Socket {
return configure(socketFactory.createSocket(Host, port) as SSLSocket)
}
override fun createSocket(Host: String, port: Int, localHost: InetAddress, localPort: Int): Socket {
return configure(socketFactory.createSocket(Host, port, localHost, localPort) as SSLSocket)
}
override fun createSocket(address: InetAddress, port: Int, localAddress: InetAddress, localPort: Int): Socket {
return configure(socketFactory.createSocket(address, port, localAddress, localPort) as SSLSocket)
}
private fun configure(socket: SSLSocket): SSLSocket {
socket.enabledProtocols = socket.supportedProtocols
socket.enabledCipherSuites = socket.supportedCipherSuites
return socket
}
}
Ich habe auch dieses Problem mit dem Fehlerbericht. Mein Code ist unten.
public static void getShop() throws Exception {
new Thread(new Runnable() {
@Override
public void run() {
try {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("https://10.0.2.2:8010/getShopInfo/aaa")
.build();
Response response = client.newCall(request).execute();
Log.d("response", response.body().string());
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
Ich habe meinen Springboot als Backend und verwende Android OKHttp, um Informationen zu erhalten. Der kritische Fehler, den ich gemacht habe, war, dass ich einen .url ( "https : //10.0.2.2: 8010/getShopInfo/aaa") im Code von Android verwende. Dem my-Backend ist aber keine https-Anfrage erlaubt. Nachdem ich .url (" http : //10.0.2.2: 8010/getShopInfo/aaa") verwendet habe, ging mein Code gut. Ich möchte also sagen, dass mein Fehler nicht die Version des Emulators ist, sondern das Anforderungsprotokoll. Nachdem ich getan habe, was ich gesagt habe, stoße ich auf ein anderes Problem, aber es ist ein anderes Problem, und ich füge die Auflösungsmethode des neuen Problems hinzu.
Viel Glück! GUY!