preface

Facebook data leak, a domestic company information leak, a domestic hotel booking records leak… In recent years, information security has become more and more worrying. As a mobile developer, it is also worrying. Under the instructions of the manager, Android information security protection begins

A webView.

In the current android application native development, in order to pursue the efficiency of development and convenience of transplantation, using WebView as the main carrier of business content display and interaction is a good compromise.

In this kind of Hybrid App, it is inevitable that JS of a page needs to call Java and call Java methods to do functions that JS of that part of the page cannot complete. Online methods can tell us that at this time we can use addjavascriptInterface to inject native interface into JS, but in android 4.2 system, this scheme has brought great security risks to our application. If an attacker executes some illegal JS on the page (inducing the user to open some phishing site to enter the risk page), it is very likely to bounce back and get shell rights on the user’s phone. The attacker can then silently install the Trojan in the background, completely penetrating the user’s phone

So how to avoid it? We optimize the webView from the following aspects.==

1. Carefully support JS functions to avoid unnecessary trouble

Android4.2 JS arbitrary code execution vulnerability, including the certificate version is too low and unsafe factors. For lower versions, it is recommended to drop support for the future of 2019.

2. Use the HTTPS link

  • The first is security;
  • The second is to avoid being hijacked by disgusting carriers to insert ads and affect the user experience

I think this is necessary, not least because security, including wechat accounts, is mandatory for developers to use HTTPS on googleplay

3. Handle file protocol security vulnerabilities

// Disable file if no support is requiredsetAllowFileAccess(false);
setAllowFileAccessFromFileURLs(false);
setAllowUniversalAccessFromFileURLs(false);
Copy the code

4. Password plaintext saving vulnerability

The webView enables the password saving function by default. When you enter a password, a dialog box is displayed asking you whether to save the password. If you choose to save the password will be stored as plain text to = = / data/data/com. Package. The name/databases/webview. Db = =, so it is in danger of being stolen password. So we should prohibit web page save password, set

WebSettings.setSavePassword(false)
Copy the code

5. Enable the secure browsing mode

<manifest> 
		<meta-data
    android:name="android.webkit.WebView.EnableSafeBrowsing"
    android:value="true" />
  		<application> ... </application>
 </manifest>

Copy the code

After the safe browsing mode is enabled, WebView will check the visited URL against the database of safe browsing malware and phishing sites, and give a danger warning before the user opens it. The experience is similar to that of Chrome. If you encounter an insecure site, you will see the following situation

Two. Communication security

This is also a top priority. Most data security is caused by network attacks, so how do we avoid it?

1. Use HTTPS

The main idea of HTTPS is to create a secure channel over an insecure network and to provide reasonable protection against eavesdropping and manin-the-middle attacks if appropriate encrypted packets and server certificates can be verified and trusted. Pretty basic level of security, if you will.

2. Verify the certificate.

There are basically two ways to implement Https on Android: one is to not authenticate the certificate, and the other is to authenticate the certificate (to prevent phishing).

  • 1. Android Web programming — HTTPS does not verify certificates (trust all certificates)
  • 2、Android: Trusting SSL certificates

The second authentication certificate is a bit more complicated and can only prevent phishing, but not effectively prevent phishing. To prevent phishing ultimately depends on users to distinguish, in the formal channels to download the application.

== However, it is also very dangerous to put the certificate in APK, because the current decompilation technology has to be satisfied, so the best way is to put the certificate in the.so file.== can further reduce the risk.

3. Do not use plaintext for communication data.

The front and back end of the custom algorithm for encryption, MD5 Base64 AES RSA, etc. == algorithm recommended.

4. Prevent caught

System.getProperty("http.proxyHost");  
System.getProperty("http.proxyPort");  

Copy the code

Normally, these two lines of code get null. If the return is not null, the agent has been suspended, and you can consider whether to discard the data

5. Tokens and other further safeguards.

While the priest climbs a post, the devil climbs ten, the road ahead will be long.

3. Data storage security

If you have data, you have to store it, and if you store it, someone else will find it. So we have to save it

1. Hide the data storage location

On an Andoid device, files or folders starting with a ‘.’ are not visible and can be read or written. If you hide the location of the stored files, you can avoid user misoperations and the chance of discovery.

2. Do not store content in plain text

Even if it is found, if it is in ciphertext, it reduces the risk of leakage

3. Do not hardcode important information in the code

Hard coding is easily found by decompilation. It is recommended to store it in.so (although.so can be cracked but is more secure than Java)

4. The storage location is recommended

Try to store it on the internal storage of the phone, not on the external memory card (because the internal storage of the phone is only open to the corresponding app, external storage is open to all apps)

Component security

Regulate the access permissions of standard Android components (Activity, Service, Receiver, Provider)

1. Set the permissions to open properties: android: exported = [” true “|” false “]

Exported attributes are common to all four components and have similar meanings. The default value depends on whether it contains ==== or not. If ==== is not included, the default value is false. If at least one ==== exists, the default value is true.

  • In the Activity:

Indicates whether external application components are allowed to start. If it is false, the Activity can only be started by the same application or different applications with the same user ID.

  • In the Service:

Indicates whether external application components are allowed to invoke or interact with the service. If it is false, the Activity can only be started by the same application or different applications with the same user ID.

  • In the Receiver:

Indicates whether messages from outside its application, such as broadcasts from the system or other applications, can be received. If false, the broadcast receiver can only receive messages sent by the same application or components of the application with the same user ID.

  • In the Provider:

Indicates whether other applications are allowed to access the content provider. If it is false, applications with the same user ID (UID) as Provider can access it. If you need to provide content to other applications, you should restrict read and write permissions.

2. Configure user-defined rights

Custom permissions, restrict their own component access, details see Android custom permissions and use

3. Use more secure and efficient LocalBroadcastManager

Different from BroadcastReceiver based on Binder, LocalBroadcastManager is implemented based on Handler, which has higher efficiency and security. Security is mainly reflected in that data is transmitted only within applications, avoiding the risks of broadcast interception, forgery, and tampering. A brief introduction to usage:

(1). Customize BroadcastReceiver

public class MyReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        //Do SomeThing Here
    }
}
Copy the code

(2). The Receive registration

MyReceiver myReceiver = new MyReceiver();
LocalBroadcastManager localBroadcastManager = LocalBroadcastManager.getInstance(this);
IntentFilter filter = new IntentFilter();
filter.addAction("MY_ACTION");
localBroadcastManager.registerReceiver(myReceiver, filter);
Copy the code

(3). Sending local broadcasts

Bundle bundle = new Bundle();
bundle.putParcelable("DATA", content);
Intent intent = new Intent();
intent.setAction("MY_ACTION");
intent.putExtras(bundle);
LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
Copy the code

(4). Unregister the Activity when it is destroyed

@Override
protected void onDestroy() {
    super.onDestroy();
    localBroadcastManager.unregisterReceiver(myReceiver);
}
Copy the code

4. Configure Application properties

(1). Debugable attribute android: debuggable = [” true “|” false “]

Many people say to manually set this value to false when publishing, but according to the official documentation, the default value is false.

(2). AllowBackup attribute android: allowBackup = [” true “|” false “]

Set whether to support backup. The default value is true. Use caution when supporting this attribute to avoid data leakage caused by backup.

5. Customize the keyboard.

In the case of dangerous input such as operation password, customized keyboard processing can be considered to prevent password theft through the keyboard.

Other protective measures

One more layer of security, one less risk.

1. Code security

  • Reinforce 360 reinforce treasure and so on
  • confusion

2. Control log output

Custom tool classes, do not appear online sensitive information

3. Vulnerability detection tool

Various cloud testing platforms for testing

  • Testin cloud measurement
  • Ali cloud test for free
  • Tencent’s wetest

4. Prevent emulators

Determine whether the phone contains bluetooth and other modules, and whether some information is inconsistent with the real phone. Prevent tampering with information through the emulator

5. Double pack

Debug application information by detecting signature information to prevent secondary packaging

6. Bind the account to the device

Bind the account to a device. If the account is inconsistent with a common device, add SMS login to log in again

7. Verify the dex file

Recompiling apk means recompiling the classes.dex file. The hash value of the generated classes.dex file has changed, so we can check the hash value of the classes.dex file to see if APK has been repackaged.

(1). Read the classes.dex file in /data/app/xxx.apk and calculate its hash value. Compare the value with the classes.dex hash value when the software is released to determine whether the client is tampered.

(2). The manifest.mf file in meta-INF directory of /data/app/xxx.apk in the application installation directory records the hash values of all files in the APK package in detail. Therefore, you can read the file to obtain the hash values of the classes.dex file and match the values with the CL when the software is released The asses. Dex hash can be compared to determine whether the client has been tampered with.

To prevent cracking, the classes.dex hashes at the time of release should be stored on the server side.

8. Debugger detection

To prevent APK from being debugged dynamically, you can check for debugger connections. The isDebuggerConnected() method is provided in the Application class to check for a debugger connection and exit the program if one is found.

9. If the root

Check whether su is included, and whether ro.secure is 1. If root is present, you can disable some core functions to check for root code

    public boolean isRoot() {
        int secureProp = getroSecureProp();
        if(secureProp == 0)// ENG /userdebug with root permissionreturn true;
        else returnisSUExist(); } private intgetroSecureProp() {
        int secureProp;
        String roSecureObj = CommandUtil.getSingleInstance().getProperty("ro.secure");
        if (roSecureObj == null) secureProp = 1;
        else {
            if ("0".equals(roSecureObj)) secureProp = 0;
            else secureProp = 1;
        }
        return secureProp;
    }

    private boolean isSUExist() {
        File file = null;
        String[] paths = {"/sbin/su"."/system/bin/su"."/system/xbin/su"."/data/local/xbin/su"."/data/local/bin/su"."/system/sd/xbin/su"."/system/bin/failsafe/su"."/data/local/su"};
        for (String path : paths) {
            file = new File(path);
            if (file.exists()) return true; // Can continue to make executable judgment}return false;
    }

Copy the code

10. Whether xPOSD frame is installed

Check whether xPOSD framework is installed, and hide core function modules if prompted. Interface to disable some functions of all schemes return to a point: == judge whether xposed package exists. == (1). Check the stack information by actively throwing an exception; (2). Is an active reflection call.

    private static final String XPOSED_HELPERS = "de.robv.android.xposed.XposedHelpers";
    private static final String XPOSED_BRIDGE = "de.robv.android.xposed.XposedBridge"; // Manually throw an exception to check whether the stack contains the XP framework package public BooleanisEposedExistByThrow() {
        try {
            throw new Exception("gg");
        } catch (Exception e) {
            for (StackTraceElement stackTraceElement : e.getStackTrace()) {
                if (stackTraceElement.getClassName().contains(XPOSED_BRIDGE)) return true;
            }
            return false; }} // Check whether xposed package exists public BooleanisXposedExists() {
        try {
            Object xpHelperObj = ClassLoader
                    .getSystemClassLoader()
                    .loadClass(XPOSED_HELPERS)
                    .newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
            return true; } catch (IllegalAccessException e) {// catch (IllegalAccessException e) {return true;
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
            return false;
        }

        try {
            Object xpBridgeObj = ClassLoader
                    .getSystemClassLoader()
                    .loadClass(XPOSED_BRIDGE)
                    .newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
            return true; } catch (IllegalAccessException e) {// catch (IllegalAccessException e) {return true;
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
            return false;
        }
        return true; } // Try to turn off xp global switchtryShutdownXposed() {
        if (isEposedExistByThrow()) {
            Field xpdisabledHooks = null;
            try {
                xpdisabledHooks = ClassLoader.getSystemClassLoader()
                        .loadClass(XPOSED_BRIDGE)
                        .getDeclaredField("disableHooks");
                xpdisabledHooks.setAccessible(true);
                xpdisabledHooks.set(null, Boolean.TRUE);
                return true;
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
                return false;
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
                return false;
            } catch (IllegalAccessException e) {
                e.printStackTrace();
                return false; }}else return true;
    }

Copy the code

The resources

  • Enable the safe browsing mode of the webView
  • Android Application Security
  • Android Security – Client security essentials
  • The official documentation
  • A pit in the Android webView
  • Android data storage security practices
  • Android: Exported attributes
  • Android Security Journey – Just a few lines of code to make Android applications more secure
  • Android application security Defense
  • Bits and pieces of Hook technology
  • Some audio and video security dribs and drabs
  • Android security/check root/ check Xposed/ anti debugging/application multi open/simulator detection