如何在Android应用程序中启用TLS 1.2支持(在Android 4.1 JB上运行)

Him*_*ani 64 ssl https android

按照Android中的文档SSLSocketSSLContext,TLS v1.1和v1.2的协议API等级16+的支持,但默认不启用. http://developer.android.com/reference/javax/net/ssl/SSLSocket.html http://developer.android.com/reference/javax/net/ssl/SSLContext.html

如何在运行Android 4.1或更高版本(但低于5.0)的设备上启用它?

我已经尝试创建一个自定义的SSLSocketFactory,它可以在Socket创建时启用所有支持的协议,并在以后使用我的自定义实现:

HttpsURLConnection.setDefaultSSLSocketFactory(new 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;
        }
    }
Run Code Online (Sandbox Code Playgroud)

但是在尝试与启用了仅TLS 1.2的服务器建立连接时,它仍会出现异常.

这是我得到的例外:

03-09 09:21:38.427:W/System.err(2496):javax.net.ssl.SSLHandshakeException:javax.net.ssl.SSLProtocolException:SSL握手中止:ssl = 0xb7fa0620:SSL库失败,通常是协议错误

03-09 09:21:38.427:W/System.err(2496):错误:14077410:SSL例程:SSL23_GET_SERVER_HELLO:sslv3警报握手失败(外部/ openssl/ssl/s23_clnt.c:741 0xa90e6990:0x00000000)

小智 19

2种启用TLSv1.1和TLSv1.2的方法:

  1. 使用此指南:http: //blog.dev-area.net/2015/08/13/android-4-1-enable-tls-1-1-and-tls-1-2/
  2. 使用此课程 https://github.com/erickok/transdroid/blob/master/app/src/main/java/org/transdroid/daemon/util/TlsSniSocketFactory.java
    schemeRegistry.register(new Scheme("https", new TlsSniSocketFactory(), port));


car*_*lol 12

我按照文章http://blog.dev-area.net/2015/08/13/android-4-1-enable-tls-1-1-and-tls-1-2中提供的说明解决了这个问题. /几乎没有变化.

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);
Run Code Online (Sandbox Code Playgroud)

这是自定义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;
    }
}
Run Code Online (Sandbox Code Playgroud)

编辑:感谢ademar111190的kotlin实现(链接)

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 }

}
Run Code Online (Sandbox Code Playgroud)

  • 嗨,它对我不起作用,知道为什么吗?如果你能帮忙,那就太好了 (2认同)
  • @AmirZiarati,后来我发现你是对的.我也从`{TLS_v1_1,TLS_v1_2}`切换到`{TLS_v1_2,TLS_v1_1}`,首先尝试使用TLS 1.2 (2认同)

saj*_*asi 10

play-services-safetynet在 android 中添加库build.gradle

implementation 'com.google.android.gms:play-services-safetynet:+'
Run Code Online (Sandbox Code Playgroud)

并将此代码添加到您的MainApplication.java

@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);
      }
    });
  }
Run Code Online (Sandbox Code Playgroud)


Vla*_*sev 7

你应该使用

 SSLContext.getInstance("TLSv1.2"); 
Run Code Online (Sandbox Code Playgroud)

对于特定的协议版本。

发生第二个异常是因为默认 socketFactory 对失败使用了回退 SSLv3 协议。

您可以使用此处的主要答案中的 NoSSLFactory 来抑制如何在 android 中为 HttpsUrlConnection 禁用 SSLv3?

此外,您应该使用所有证书(客户端和受信任的证书,如果需要)初始化 SSLContext

但如果不使用,所有这些都是无用的

ProviderInstaller.installIfNeeded(getContext())
Run Code Online (Sandbox Code Playgroud)

这是有关正确使用场景的更多信息 https://developer.android.com/training/articles/security-gms-provider.html

希望能帮助到你。

  • 根据这个 - http://grepcode.com/file/repo1.maven.org/maven2/org.ektorp/org.ektorp.android/1.2.2/org/ektorp/android/http/AndroidSSLSocketFactory.java?av= h#AndroidSSLSocketFactory - 只接受 `"TLS"`、`"SSL"` 和 `"SSLV2"`。 (2认同)

Nav*_*hna 5

我对上面提到的答案有一些补充它实际上是来自okhttp的Jesse Wilson提到的黑客,这里是方形.根据这个hack,我不得不将我的SSLSocketFactory变量重命名为

private SSLSocketFactory delegate;
Run Code Online (Sandbox Code Playgroud)

这是我的TLSSocketFactory

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;
}
}
Run Code Online (Sandbox Code Playgroud)

这就是我用okhttp和改造它的方式

 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();
Run Code Online (Sandbox Code Playgroud)