Gemäß den Dokumenten in Android für SSLSocket
und SSLContext
werden die Protokolle TLS v1.1 und v1.2 in API-Level 16+ unterstützt, sind jedoch standardmäßig nicht aktiviert. http://developer.Android.com/reference/javax/net/ssl/SSLSocket.htmlhttp://developer.Android.com/reference/javax/net/ssl/SSLContext.html
Wie aktiviere ich es auf einem Gerät mit Android 4.1 oder höher (aber unter 5.0)?
Ich habe versucht, eine benutzerdefinierte SSLSocketFactory zu erstellen, die alle unterstützten Protokolle aktiviert, wenn Socket
erstellt werden, und später meine benutzerdefinierte Implementierung verwendet als:
HttpsURLConnection.setDefaultSSLSocketFactory (neues MySSLSocketFactory ());
public class MySSLSocketFactory extends SSLSocketFactory {
private SSLContext sc;
private SSLSocketFactory ssf;
public MySSLSocketFactory() {
try {
sc = SSLContext.getInstance("TLS");
sc.init(null, null, null);
ssf = sc.getSocketFactory();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (KeyManagementException e) {
e.printStackTrace();
}
}
@Override
public Socket createSocket(Socket s, String Host, int port, boolean autoClose)
throws IOException {
SSLSocket ss = (SSLSocket) ssf.createSocket(s, Host, port, autoClose);
ss.setEnabledProtocols(ss.getSupportedProtocols());
ss.setEnabledCipherSuites(ss.getSupportedCipherSuites());
return ss;
}
@Override
public String[] getDefaultCipherSuites() {
return ssf.getDefaultCipherSuites();
}
@Override
public String[] getSupportedCipherSuites() {
return ssf.getSupportedCipherSuites();
}
@Override
public Socket createSocket(String Host, int port) throws IOException, UnknownHostException {
SSLSocket ss = (SSLSocket) ssf.createSocket(Host, port);
ss.setEnabledProtocols(ss.getSupportedProtocols());
ss.setEnabledCipherSuites(ss.getSupportedCipherSuites());
return ss;
}
@Override
public Socket createSocket(InetAddress Host, int port) throws IOException {
SSLSocket ss = (SSLSocket) ssf.createSocket(Host, port);
ss.setEnabledProtocols(ss.getSupportedProtocols());
ss.setEnabledCipherSuites(ss.getSupportedCipherSuites());
return ss;
}
@Override
public Socket createSocket(String Host, int port, InetAddress localHost, int localPort)
throws IOException, UnknownHostException {
SSLSocket ss = (SSLSocket) ssf.createSocket(Host, port, localHost, localPort);
ss.setEnabledProtocols(ss.getSupportedProtocols());
ss.setEnabledCipherSuites(ss.getSupportedCipherSuites());
return ss;
}
@Override
public Socket createSocket(InetAddress address, int port, InetAddress localAddress,
int localPort) throws IOException {
SSLSocket ss = (SSLSocket) ssf.createSocket(address, port, localAddress, localPort);
ss.setEnabledProtocols(ss.getSupportedProtocols());
ss.setEnabledCipherSuites(ss.getSupportedCipherSuites());
return ss;
}
}
Bei dem Versuch, eine Verbindung mit einem Server herzustellen, auf dem Nur TLS 1.2 aktiviert ist, tritt dennoch eine Ausnahme auf.
Hier ist die Ausnahme, die ich bekomme:
03-09 09: 21: 38.427: W/System.err (2496): javax.net.ssl.SSLHandshakeException: javax.net.ssl.SSLProtocolException: SSL-Handshake abgebrochen: ssl = 0xb7fa0620: Fehler in der SSL-Bibliothek, normalerweise ein Protokoll Error
03-09 09: 21: 38.427: W/System.err (2496): Fehler: 14077410: SSL-Routinen: SSL23_GET_SERVER_HELLO: SSLV3-Warnungs-Handshake-Fehler (external/openssl/ssl/s23_clnt.c: 741 0xa90e6990: 0x00000000)
Zwei Möglichkeiten zum Aktivieren von TLSv1.1 und TLSv1.2:
schemeRegistry.register(new Scheme("https", new TlsSniSocketFactory(), port));
Ich habe dieses Problem mit den Angaben in Artikel http://blog.dev-area.net/2015/08/13/Android-4-1-enable-tls-1-1-and-tls-1 gelöst -2/ mit kleinen Änderungen.
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, null, null);
SSLSocketFactory noSSLv3Factory = null;
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KitKat) {
noSSLv3Factory = new TLSSocketFactory(sslContext.getSocketFactory());
} else {
noSSLv3Factory = sslContext.getSocketFactory();
}
connection.setSSLSocketFactory(noSSLv3Factory);
Dies ist der Code der benutzerdefinierten TLSSocketFactory:
public static class TLSSocketFactory extends SSLSocketFactory {
private SSLSocketFactory internalSSLSocketFactory;
public TLSSocketFactory(SSLSocketFactory delegate) throws KeyManagementException, NoSuchAlgorithmException {
internalSSLSocketFactory = delegate;
}
@Override
public String[] getDefaultCipherSuites() {
return internalSSLSocketFactory.getDefaultCipherSuites();
}
@Override
public String[] getSupportedCipherSuites() {
return internalSSLSocketFactory.getSupportedCipherSuites();
}
@Override
public Socket createSocket(Socket s, String Host, int port, boolean autoClose) throws IOException {
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(s, Host, port, autoClose));
}
@Override
public Socket createSocket(String Host, int port) throws IOException, UnknownHostException {
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(Host, port));
}
@Override
public Socket createSocket(String Host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException {
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(Host, port, localHost, localPort));
}
@Override
public Socket createSocket(InetAddress Host, int port) throws IOException {
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(Host, port));
}
@Override
public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(address, port, localAddress, localPort));
}
/*
* Utility methods
*/
private static Socket enableTLSOnSocket(Socket socket) {
if (socket != null && (socket instanceof SSLSocket)
&& isTLSServerEnabled((SSLSocket) socket)) { // skip the fix if server doesn't provide there TLS version
((SSLSocket) socket).setEnabledProtocols(new String[]{TLS_v1_1, TLS_v1_2});
}
return socket;
}
private static boolean isTLSServerEnabled(SSLSocket sslSocket) {
System.out.println("__prova__ :: " + sslSocket.getSupportedProtocols().toString());
for (String protocol : sslSocket.getSupportedProtocols()) {
if (protocol.equals(TLS_v1_1) || protocol.equals(TLS_v1_2)) {
return true;
}
}
return false;
}
}
Edit: Danke an ademar111190 für die Kotlin-Implementierung ( link )
class TLSSocketFactory constructor(
private val internalSSLSocketFactory: SSLSocketFactory
) : SSLSocketFactory() {
private val protocols = arrayOf("TLSv1.2", "TLSv1.1")
override fun getDefaultCipherSuites(): Array<String> = internalSSLSocketFactory.defaultCipherSuites
override fun getSupportedCipherSuites(): Array<String> = internalSSLSocketFactory.supportedCipherSuites
override fun createSocket(s: Socket, Host: String, port: Int, autoClose: Boolean) =
enableTLSOnSocket(internalSSLSocketFactory.createSocket(s, Host, port, autoClose))
override fun createSocket(Host: String, port: Int) =
enableTLSOnSocket(internalSSLSocketFactory.createSocket(Host, port))
override fun createSocket(Host: String, port: Int, localHost: InetAddress, localPort: Int) =
enableTLSOnSocket(internalSSLSocketFactory.createSocket(Host, port, localHost, localPort))
override fun createSocket(Host: InetAddress, port: Int) =
enableTLSOnSocket(internalSSLSocketFactory.createSocket(Host, port))
override fun createSocket(address: InetAddress, port: Int, localAddress: InetAddress, localPort: Int) =
enableTLSOnSocket(internalSSLSocketFactory.createSocket(address, port, localAddress, localPort))
private fun enableTLSOnSocket(socket: Socket?) = socket?.apply {
if (this is SSLSocket && isTLSServerEnabled(this)) {
enabledProtocols = protocols
}
}
private fun isTLSServerEnabled(sslSocket: SSLSocket) = sslSocket.supportedProtocols.any { it in protocols }
}
Ich habe einige Ergänzungen zu den oben genannten Antworten. Es handelt sich um einen Hack, den Jesse Wilson von okhttp, square hier erwähnt hat. Entsprechend diesem Hack musste ich meine SSLSocketFactory-Variable in umbenennen
private SSLSocketFactory delegate;
Dies ist meine TLSSocketFactory Klasse
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 so habe ich es mit okhttp und retrofit benutzt
OkHttpClient client=new OkHttpClient();
try {
client = new OkHttpClient.Builder()
.sslSocketFactory(new TLSSocketFactory())
.build();
} catch (KeyManagementException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(URL)
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build();
Du solltest benutzen
SSLContext.getInstance("TLSv1.2");
für bestimmte Protokollversion.
Die zweite Ausnahme trat auf, weil default socketFactory das Fallback-SSLv3-Protokoll für Fehler verwendet hat.
Sie können NoSSLFactory aus der Hauptantwort hier zur Unterdrückung verwenden Wie kann ich SSLv3 in Android für HttpsUrlConnection deaktivieren?
Außerdem sollten Sie SSLContext mit allen Ihren Zertifikaten (Client und vertrauenswürdig, falls Sie sie benötigen) initiieren.
Aber das alles ist ohne Verwendung nutzlos
ProviderInstaller.installIfNeeded(getContext())
Hier finden Sie weitere Informationen zum richtigen Einsatzszenario https://developer.Android.com/training/articles/security-gms-provider.html
Ich hoffe es hilft.
Wie das OP bereits sagte, werden die Protokolle TLS v1.1 und v1.2 in API-Level 16+ unterstützt, sind jedoch nicht standardmäßig aktiviert, sondern müssen nur aktiviert werden.
In diesem Beispiel wird HttpsUrlConnection
und nicht HttpUrlConnection
verwendet. Folgen Sie https://blog.dev-area.net/2015/08/13/Android-4-1-enable-tls-1-1-and-tls-1-2/ , wir können eine erstellen Fabrik
class MyFactory extends SSLSocketFactory {
private javax.net.ssl.SSLSocketFactory internalSSLSocketFactory;
public MyFactory() throws KeyManagementException, NoSuchAlgorithmException {
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, null, null);
internalSSLSocketFactory = context.getSocketFactory();
}
@Override
public String[] getDefaultCipherSuites() {
return internalSSLSocketFactory.getDefaultCipherSuites();
}
@Override
public String[] getSupportedCipherSuites() {
return internalSSLSocketFactory.getSupportedCipherSuites();
}
@Override
public Socket createSocket() throws IOException {
return enableTLSOnSocket(internalSSLSocketFactory.createSocket());
}
@Override
public Socket createSocket(Socket s, String Host, int port, boolean autoClose) throws IOException {
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(s, Host, port, autoClose));
}
@Override
public Socket createSocket(String Host, int port) throws IOException, UnknownHostException {
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(Host, port));
}
@Override
public Socket createSocket(String Host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException {
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(Host, port, localHost, localPort));
}
@Override
public Socket createSocket(InetAddress Host, int port) throws IOException {
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(Host, port));
}
@Override
public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
return enableTLSOnSocket(internalSSLSocketFactory.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;
}
}
Unabhängig davon, welche Netzwerkbibliothek Sie verwenden, stellen Sie sicher, dass ((SSLSocket)socket).setEnabledProtocols(new String[] {"TLSv1.1", "TLSv1.2"});
aufgerufen wird, damit der Socket TLS-Protokolle aktiviert hat.
Jetzt können Sie das in HttpsUrlConnection
verwenden
class MyHttpRequestTask extends AsyncTask<String,Integer,String> {
@Override
protected String doInBackground(String... params) {
String my_url = params[0];
try {
URL url = new URL(my_url);
HttpsURLConnection httpURLConnection = (HttpsURLConnection) url.openConnection();
httpURLConnection.setSSLSocketFactory(new MyFactory());
// setting the Request Method Type
httpURLConnection.setRequestMethod("GET");
// adding the headers for request
httpURLConnection.setRequestProperty("Content-Type", "application/json");
String result = readStream(httpURLConnection.getInputStream());
Log.e("My Networking", "We have data" + result.toString());
}catch (Exception e){
e.printStackTrace();
Log.e("My Networking", "Oh no, error occurred " + e.toString());
}
return null;
}
private static String readStream(InputStream is) throws IOException {
final BufferedReader reader = new BufferedReader(new InputStreamReader(is, Charset.forName("US-ASCII")));
StringBuilder total = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
total.append(line);
}
if (reader != null) {
reader.close();
}
return total.toString();
}
}
Zum Beispiel
new MyHttpRequestTask().execute(myUrl);
Denken Sie auch daran, minSdkVersion
in build.gradle auf 16 zu setzen
minSdkVersion 16
play-services-safetynet
Bibliothek in Android build.gradle
hinzufügen:
implementation 'com.google.Android.gms:play-services-safetynet:+'
und füge diesen Code zu deinem MainApplication.Java
hinzu:
@Override
public void onCreate() {
super.onCreate();
upgradeSecurityProvider();
SoLoader.init(this, /* native exopackage */ false);
}
private void upgradeSecurityProvider() {
ProviderInstaller.installIfNeededAsync(this, new ProviderInstallListener() {
@Override
public void onProviderInstalled() {
}
@Override
public void onProviderInstallFailed(int errorCode, Intent recoveryIntent) {
// GooglePlayServicesUtil.showErrorNotification(errorCode, MainApplication.this);
GoogleApiAvailability.getInstance().showErrorNotification(MainApplication.this, errorCode);
}
});
}
@ Inherently Curious - Vielen Dank für den Beitrag. Sie sind fast da - Sie müssen der Methode SSLContext.init () zwei weitere Parameter hinzufügen.
TrustManager[] trustManagers = new TrustManager[] { new TrustManagerManipulator() };
sc.init(null, trustManagers, new SecureRandom());
es wird anfangen zu arbeiten. Nochmals vielen Dank für das Posten. Ich habe dieses/mein Problem mit Ihrem Code gelöst.