在 Android OS 4.4.2/MobileFirst 混合应用程序上启用 TLS 1.2

Posted

技术标签:

【中文标题】在 Android OS 4.4.2/MobileFirst 混合应用程序上启用 TLS 1.2【英文标题】:Enable TLS 1.2 on Android OS 4.4.2/ MobileFirst Hybrid application 【发布时间】:2017-07-20 18:54:53 【问题描述】:

我们有在 MobileFirst 7.1.0.00.20170627-0807 上运行的移动混合项目。

我们更改了服务器配置以停止支持 TLS 1.0 和 1.1,并强制它使用 TLS 1.2,这破坏了我们在 android 设备 4.4.2 上运行的移动应用程序,因为它需要基于以下参考的原生开发来支持它:

ANDROID VERSIONS 4.4.2 AND EARLIER CANNOT CONNECT TO SERVER USING HTTPS IF ONLY TLS 1.2 IS ENABLED

我们尝试了以下博客中提到的多种解决方案,但都没有成功:

Custom SSLSocketFactory Implementation to enable tls 1.1 and tls 1.2 for android 4.1 (16+)

How to enable TLS 1.2 support in an Android application

在我的原生代码目录ca.company.project我添加了一个Java文件来支持自定义的SSLSocketFactory:

package ca.company.project;

import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;

/**
 * @author fkrauthan
 */
public class TLSSocketFactory extends SSLSocketFactory 

    private SSLSocketFactory internalSSLSocketFactory;

    public TLSSocketFactory() 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;
    

在同一目录 MobileBanking.java 下的本机代码中,我为 onCreate() 添加了以下代码:

 package ca.company.project;

    import org.apache.cordova.CordovaActivity;

    import android.app.Activity;
    import android.app.AlertDialog;
    import android.content.Context;
    import android.content.DialogInterface;
    import android.content.DialogInterface.OnClickListener;
    import android.content.pm.ActivityInfo;
    import android.content.res.Configuration;
    import android.os.Bundle;
    import android.util.DisplayMetrics;
    import android.view.WindowManager.LayoutParams;
    import android.content.pm.PackageManager;
    import com.adobe.mobile.*;

    import com.worklight.androidgap.api.WL;
    import com.worklight.androidgap.api.WLInitWebFrameworkListener;
    import com.worklight.androidgap.api.WLInitWebFrameworkResult;
    import com.worklight.wlclient.api.WLClient;


    import javax.net.ssl.SSLSocketFactory;

    import java.security.KeyManagementException;
    import java.security.NoSuchAlgorithmException;
    import java.security.SecureRandom;
    import java.security.cert.CertificateException;
    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;


    import android.os.*;

    public class MobileBanking extends CordovaActivity implements WLInitWebFrameworkListener 

        @Override
        public void onCreate(Bundle savedInstanceState)
            super.onCreate(savedInstanceState);


            /*getWindow().setFlags(LayoutParams.FLAG_SECURE,
                    LayoutParams.FLAG_SECURE);*/

            WL.createInstance(this);


    try
        SSLContext sslContext = SSLContext.getInstance("TLS");
        sslContext.init(null, null, null);
        SSLSocketFactory noSSLv3Factory = null;
        if (android.os.Build.VERSION.SDK_INT <= android.os.Build.VERSION_CODES.KITKAT) 
            noSSLv3Factory = new TLSSocketFactory();
         else 
            noSSLv3Factory = sslContext.getSocketFactory();
        
        HttpsURLConnection.setDefaultSSLSocketFactory(noSSLv3Factory);

      catch (NoSuchAlgorithmException e) 
        e.printStackTrace();
     catch (KeyManagementException e) 
        e.printStackTrace();
    




            WL.getInstance().showSplashScreen(this);

            WL.getInstance().initializeWebFramework(getApplicationContext(), this);

            if(isTabletDevice(this))
                //Tablet
    //          System.out.println("isTablet oncreate");
            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);
             else 
                //Phone
                 setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
            
            // Allow the SDK access to the application context
            Config.setContext(this.getApplicationContext());
        

它不起作用,知道我缺少什么或需要更改什么吗?

【问题讨论】:

【参考方案1】:

我无法立即对您提供的代码发表评论,但我知道这里有一个解决方案,它适用于面临相同问题的另一位 MFP 用户:

1) 转到GitHub repo,并获取“TlsSniSocketFactory.java”、“IgnoreSSLTrustManager.java”和“SelfSignedTrustManager.java”中的类。请记住,此开源代码并非由 IBM 提供,IBM 也不对其提供任何支持。

2) 在您的应用程序中包含这些类 - 更改包名称以与您的应用程序一致。

3) 在扩展 CordovaActivity 的应用程序主活动中包含此方法:

private void replaceSocketFactory(LayeredSocketFactory tlsSocketFactory) 
        HttpClientManager manager = HttpClientManager.getInstance();
        HttpClient client=  manager.getHttpClient();
        SchemeRegistry schemeRegistry =  client.getConnectionManager().getSchemeRegistry();  
        Scheme httpsScheme = schemeRegistry.getScheme("https");
        schemeRegistry.unregister("https");
        Scheme newScheme = new Scheme("https", tlsSocketFactory, httpsScheme.getDefaultPort());
        schemeRegistry.register(newScheme);
    

4) 在 WL.createInstance(this) 之后从 Activity.onCreate() 方法调用此方法;

@Override
    public void onCreate(Bundle savedInstanceState)
        super.onCreate(savedInstanceState);

        WL.createInstance(this);
        replaceSocketFactory(new TlsSniSocketFactory());

        WL.getInstance().showSplashScreen(this);

        WL.getInstance().initializeWebFramework(getApplicationContext(), this);
    

我不确定您为什么会看到此问题,因为您使用的 MFP 7.1 版本包含此问题的修复程序。如果您之前从不包含该修复程序的 iFix 版本更新,您可能需要从应用程序中删除“android”环境并重新添加它。

【讨论】:

感谢您的回复,只是为了澄清一下,您是说我们的 MFP 服务器应该修复此问题,而无需任何额外的本机编码?我们已经删除了 android 环境,使用上面提供的 MFP 版本重新创建了它,再次导入了类,但仍然是同样的问题。您是否建议打开 PMR?另一方面,上面的代码对我们不起作用,我们仍在尝试找出原因。 您提到的 APAR 的修复首先出现在 MFP 7.1 IF20160709-0639(以及更高版本)中,因此您应该不会遇到此问题,并且不必进行任何额外的本机编码。请注意,这是一个 SDK 修复,而不是服务器修复 - 因此您用于构建应用程序的 MFP Studio(或 CLI)版本必须是 IF20160709-0639 或更高版本,使用中的服务器构建对此问题没有影响. 如果您仍然看到此问题,您很可能遇到了不同的问题(与该 APAR 纠正的问题不同)。如果需要进行详细调查,则开设 PMR 是一个合理的选择。 谢谢,我的 CLI 版本是:[echo] Worklight Ant 任务版本 7.1.0.00.20170627-0807。我再次重新创建了android env并签署了apk,将它安装在两个模拟器上,一个运行4.4.2,另一个运行5.0。 5.0 工作但 4.4.2 抛出此错误(共享日志文件):dropbox.com/s/0jdk9rct6s05v7k/ADB_LogCat_1.txt?dl=0 感谢您提供日志。如果可能,我建议打开 PMR - 日志中的错误是由证书固定代码生成的,我不确定我们一直在讨论的 APAR 修复是否会影响该代码路径。在不使用证书固定的情况下尝试此操作并查看是否生成相同类型的错误可能是一个有趣的实验。

以上是关于在 Android OS 4.4.2/MobileFirst 混合应用程序上启用 TLS 1.2的主要内容,如果未能解决你的问题,请参考以下文章

致命异常:android.app.RemoteServiceException:无法在 android.os.Handler.dispatchMessage 传送广播

如何修复 android.os.NetworkOnMainThread [重复]

android.os.NetworkOnMainThreadException

Android 在 OS 2.3 上选择和裁剪图像

android.os.NetworkOnMainThreadException

android.os.TransactionTooLargeException 与作物活动