web-dev-qa-db-ja.com

AndroidアプリケーションでTLS 1.2サポートを有効にする方法(Android 4.1 JBで実行)

Android for SSLSocketおよびSSLContextのドキュメントに従って、TLS v1.1およびv1.2プロトコルはAPIレベル16+でサポートされていますが、デフォルトでは有効になっていません。 http://developer.Android.com/reference/javax/net/ssl/SSLSocket.htmlhttp://developer.Android.com/reference/javax/net/ssl/ SSLContext.html

Android 4.1以降(5.0以下)を実行しているデバイスで有効にするにはどうすればよいですか?

Socketの作成時にサポートされているすべてのプロトコルを有効にし、後でカスタム実装を次のように使用するカスタムSSLSocketFactoryを作成しようとしました。

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

ただし、TLS 1.2のみが有効になっているサーバーとの接続を確立しようとすると、例外が発生します。

私が得る例外はここにあります:

03-09 09:21:38.427:W/System.err(2496):javax.net.ssl.SSLHandshakeException:javax.net.ssl.SSLProtocolException:SSL handshake aborted:ssl = 0xb7fa0620:SSLライブラリ、通常はプロトコルの失敗エラー

03-09 09:21:38.427:W/System.err(2496):error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure(external/openssl/ssl/s23_clnt.c:741 0xa90e6990:0x00000000)

62

TLSv1.1およびTLSv1.2を有効にする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));
19
tran minh linh

私は記事で提供された指示に従ってこの問題を解決しました 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);

これは、カスタム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;
    }
}

編集:kotlinの実装のためのademar111190に感謝します( リンク

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 }

}
12
carlol

上記の回答にいくつかの追加があります。その事実は、okhttpのJesse Wilsonによるハック、正方形 here です。このハックによると、SSLSocketFactory変数の名前を

private SSLSocketFactory delegate;

これは私の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;
}
}

そして、これは私が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();
5
Navneet Krishna

あなたが使用する必要があります

 SSLContext.getInstance("TLSv1.2"); 

特定のプロトコルバージョン用。

2番目の例外は、デフォルトのsocketFactoryがフォールバックSSLv3プロトコルを使用して失敗したために発生しました。

あなたはその抑制のためにここの主な答えからNoSSLFactoryを使用することができます HttpsUrlConnectionのAndroidでSSLv3を無効にする方法?

また、すべての証明書(必要な場合はクライアント証明書と信頼証明書)でSSLContextを初期化する必要があります

しかし、それはすべて使用せずに無駄です

ProviderInstaller.installIfNeeded(getContext())

適切な使用シナリオの詳細はこちら https://developer.Android.com/training/articles/security-gms-provider.html

それが役に立てば幸い。

4

OPが述べたように、TLS v1.1およびv1.2プロトコルはAPIレベル16+でサポートされていますが、デフォルトでは有効になっていないため、有効にする必要があります。

ここの例では、HttpsUrlConnectionではなくHttpUrlConnectionを使用しています。 https://blog.dev-area.net/2015/08/13/Android-4-1-enable-tls-1-1-and-tls-1-2/ に従ってください。工場を作成できます

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

使用するネットワークライブラリに関係なく、((SSLSocket)socket).setEnabledProtocols(new String[] {"TLSv1.1", "TLSv1.2"});が呼び出され、ソケットがTLSプロトコルを有効にしていることを確認してください。

これで、HttpsUrlConnectionで使用できます

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

例えば

new MyHttpRequestTask().execute(myUrl);

また、build.gradleのminSdkVersionを16に上げてください。

minSdkVersion 16
0
onmyway133

Android play-services-safetynetbuild.gradleライブラリを追加します。

implementation 'com.google.Android.gms:play-services-safetynet:+'

このコードを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);
      }
    });
  }
0
sajad abbasi

@Inherently Curious-これを投稿してくれてありがとう。もうすぐです-SSLContext.init()メソッドにさらに2つのパラメーターを追加する必要があります。

TrustManager[] trustManagers = new TrustManager[] { new TrustManagerManipulator() };
sc.init(null, trustManagers, new SecureRandom());

動作を開始します。再びこれを投稿してくれてありがとう。あなたのコードでこの問題を解決しました。

0