How to detect Jailbroken or Rooted device and hide sensitive data in background?

The following recipes relate to security of Codename One apps. This includes detecting Jailbroken or Rooted device and hiding sensitive data when entering background. Jump To Topic The following recipes include tips on making your Codename One apps more secure. Detecting Jailbroken/Rooted Device Problem You want to detect whether the device your app is running […]

The following recipes relate to security of Codename One apps. This includes detecting Jailbroken or Rooted device and hiding sensitive data when entering background.

Jump To Topic

The following recipes include tips on making your Codename One apps more secure.

Detecting Jailbroken/Rooted Device

Problem

You want to detect whether the device your app is running on is Jailbroken or Rooted.

Solution

While there is no way to know whether the device is rooted with 100% certainty, you can use the CN1JailbreakDetect cn1lib to to make a good guess.

This cn1lib acts as a thin wrapper around the RootBeer Android library, and DTTJailbreakDetection iOS library, which employ heuristics to determine whether the device has likely been jailbroken.

Example

				
					package com.codename1.samples;


import com.codename1.ext.jailbreak.JailbreakDetect;
import static com.codename1.ui.CN.*;
import com.codename1.ui.Display;
import com.codename1.ui.Form;
import com.codename1.ui.Dialog;
import com.codename1.ui.Label;
import com.codename1.ui.plaf.UIManager;
import com.codename1.ui.util.Resources;
import com.codename1.io.Log;
import com.codename1.ui.Toolbar;
import java.io.IOException;
import com.codename1.ui.layouts.BoxLayout;
import com.codename1.io.NetworkEvent;
import com.codename1.ui.Button;
import com.codename1.ui.Command;


public class JailbreakDetectionSample {

    private Form current;
    private Resources theme;

    public void init(Object context) {
        // use two network threads instead of one
        updateNetworkThreadCount(2);

        theme = UIManager.initFirstTheme("/theme");

        // Enable Toolbar on all Forms by default
        Toolbar.setGlobalToolbar(true);

        // Pro only feature
        Log.bindCrashProtection(true);

        addNetworkErrorListener(err -> {
            // prevent the event from propagating
            err.consume();
            if(err.getError() != null) {
                Log.e(err.getError());
            }
            Log.sendLogAsync();
            Dialog.show("Connection Error", "There was a networking error in the connection to " + err.getConnectionRequest().getUrl(), "OK", null);
        });
    }

    public void start() {
        if(current != null){
            current.show();
            return;
        }
        Form hi = new Form("Jailbreak Detection", BoxLayout.y());
        Button detect = new Button("Detect Jailbreak");
        detect.addActionListener(evt->{
            if (JailbreakDetect.isJailbreakDetectionSupported()) {
                if (JailbreakDetect.isJailbroken()) {
                    Dialog.show("Jailbroken","This device is jailbroken", new Command("OK") );
                } else {
                    Dialog.show("Not Jailbroken", "Probably not jailbroken.  But can't be 100% sure.", new Command("OK"));
                }
            } else {
                Dialog.show("No Idea", "No support for jailbreak detection on this device.", new Command("OK"));
            }
        });
        hi.add(detect);
        hi.show();
    }

    public void stop() {
        current = getCurrentForm();
        if(current instanceof Dialog) {
            ((Dialog)current).dispose();
            current = getCurrentForm();
        }
    }

    public void destroy() {
    }

}
				
			

Tip:

This sample is part of the Codename One samples project, and can be run directly from the Codename One SampleRunner.

Discussion

The CN1JailbreakDetect provides two useful static methods for jailbreak detection:

1. isJailbreakDetectionSupported() – This checks if the jailbreak detection is even supported on this platform.

2. isJailBroken() – This checks if the device is jailbroken. If detection is not supported, then this will always return false.

Currently jailbreak detection is only supported on Android and iOS.

Important:

There is NO way to know with 100% certainty whether or not a device has been jailbroken.

Further Reading

Hiding Sensitive Data When Entering Background

Problem

iOS will take a screenshot of your app when it enters the background that it uses for various previews of the app state. You want to hide sensitive data in your app’s UI to prevent this information from leaking out via these screenshots.

Solution

You can use the ios.blockScreenshotsOnEnterBackground=true build hint to prevent iOS from taking screenshots app goes into the background. This will cause the canvas on which the Codename One UI is drawn to be hidden in the didEnterBackground hook and unhidden in the willEnterForeground hook.

Warning:

This will cause your app to appear as a blank white rectangle when the user is browsing through opened apps.

Hiding Sensitive Data When Entering Background

Figure 1. Notice the app in the middle is blank white because it has been set to block iOS screenshots.

Discussion

You might have been tempted to try to modify the UI inside the stop() lifecycle method of your app, since it is called itself by the didEnterBackground hook.

This strategy will work in some platforms, but not on iOS because the screenshot call is made immediately upon the didEnterBackground method returning – and the stop() method runs on the EDT (a different thread), so this is not possible.

Source: CodeName One