Device Security

Introduction to the Device Security Service

The Device Security service allows you to easily configure and manage device security, and trust checks for your mobile application

  • Perform a range of device trust checks on the mobile device, such as checking if the device is rooted, and allows you take proactive action based on the results

  • Distribute SSL certificates with a mobile app to create a direct chain of trust (certificate pinning)

Device Security is not currently associated with an OpenShift service, so there are no provisioning or binding tasks associated with using Device Security.

Configuring your Development Environment for the Device Security Service

Downloading the Mobile Services Configuration File

  1. Navigate to your project in OpenShift.

  2. On the Overview screen, expand your Mobile Client to view the CLIENT INFO.

  3. Copy the configuration to your clipboard.

  4. Save the contents of the clipboard to a new file called mobile-services.json.

    The mobile-services.json file is the link between your provisioned services on OpenShift and the mobile app you are developing. This file provides all required configuration to initialise the various SDKs and get them hooked up/connected to the back-end services.
  5. Follow the next specific additional instructions depending on your platform:

Android

Locate this file at the following location in your application project:

app/src/main/assets/mobile-services.json

iOS

Locate this file at the following location in your application project:

<app directory>/mobile-services.json

Cordova

Locate this file in your application project and import it using require.

const aerogearConfig = require("./mobile-services.json");

Alternatively you can create a JavaScript object and use directly:

const aerogearConfig = /* Paste here the contents of the clipboard */;
Xamarin

Locate this file at the following location in your application project:

Resources/mobile-services.json

Setting up Device Security service SDK

Importing the libraries

Android
  1. Add the following dependency in your app’s build.gradle:

    dependencies {
        implementation 'org.aerogear:android-security:1.0.0'
    }
  2. Get an instance of SecurityService to start using the SDK.

    SecurityService securityService = MobileCore.getInstance(SecurityService.class);
    Any subsequent call to MobileCore#getInstance returns the same instance of SecurityService.
iOS
  1. Add the dependency to your Podfile

    target '[TARGET NAME]' do
        pod 'AGSSecurity', '1.0.0'
    end
  2. Update the dependencies by running in your terminal

    $ pod install
  3. Import AGSSecurity and instantiate the SecurityService to start using the SDK

    import AGSSecurity
    
    let security = AGSSecurity()
    Any subsequent call to AGSSecurity returns the same instance of the SecurityService.
Cordova
  1. Install the AeroGear Security package from NPM

    $ npm install @aerogear/security
  2. Add the AeroGear Security plugin for Cordova:

    $ cordova plugin add @aerogear/cordova-plugin-aerogear-security
  3. Import and instantiate SecurityService to start using the SDK:

    const SecurityService = require("@aerogear/security");
    
    const securityService = new SecurityService();
    Any new instantiation of SecurityService returns the same instance.
Xamarin
  1. Install NuGet

  2. Install the AeroGear Security package

    $ dotnet add package AeroGear.Mobile.Security --version 1.0.0
  3. Install the specific packages for Android:

    $ dotnet add package AeroGear.Mobile.Security.Platform.Android --version 1.0.0

    And for iOS:

    $ dotnet add package AeroGear.Mobile.Security.Platform.iOS --version 1.0.0
  4. Initialize the SDK by adding the following line to your Android application’s MainActivity.cs:

    protected override void OnCreate(Bundle savedInstanceState)
    {
        base.OnCreate(savedInstanceState);
    
        SecurityService.InitializeService();
        // ...
    }

    And to your iOS application’s AppDelegate.cs:

    public override bool FinishedLaunching(UIApplication app, NSDictionary options)
    {
        SecurityService.InitializeService();
        // ...
    }
  5. Get an instance of SecurityService to start using the SDK:

    var securityService = MobileCore.GetService<SecurityService>();
    Any subsequent call to MobileCore#getInstance returns the same instance of SecurityService.

Performing Device Trust Checks in your Device

This section describes what Device Trust Checks are available and how to execute them for the supported platforms. Also, mind that Security Checks can be performed either individually or together.

A successful check means that the environment the application is running in is more secure and no action is required, as opposed to signalling if a certain feature is enabled. For example, the Root Access Detection Check NOT_ROOTED should return true when it is not rooted, since this would be the more secure condition.

Root Access Detection

Use this to help prevent your app running in a device that has been rooted/jailbroken.

Android
SecurityService securityService = MobileCore.getInstance(SecurityService.class);

SecurityCheckResult result = securityService.check(SecurityCheckType.NOT_ROOTED);
iOS
let security = AGSSecurity()
let result = security.check(IsJailbrokenCheck())
Cordova
new SecurityService()
    .check(SecurityCheckType.notRooted)
    .then(result => {
        // Handle the security result metric
        // result: { id: string, name: string, passed: boolean }
    });
Xamarin

Use NOT_ROOTED for Android:

var securityService = MobileCore.GetService<SecurityService>();

SecurityCheckResult result = securityService.Check(SecurityChecks.NOT_ROOTED);

Use NOT_JAILBROKEN for iOS:

var securityService = MobileCore.GetService<SecurityService>();

SecurityCheckResult result = securityService.Check(SecurityChecks.NOT_JAILBROKEN);

Developer Mode Detection

Use this to detect if Developer Mode has been enabled on the device.

Android
SecurityService securityService = MobileCore.getInstance(SecurityService.class);

SecurityCheckResult result = securityService.check(SecurityCheckType.NO_DEVELOPER_MODE);
iOS

This check is not available for iOS.

Cordova

This check is not available for Cordova.

Xamarin
This check is available for Android only.
var securityService = MobileCore.GetService<SecurityService>();

SecurityCheckResult result = securityService.Check(SecurityChecks.NO_DEVELOPER_MODE);

Debugger Detection

Use this to detect if a debugger is attached to the app.

Android
SecurityService securityService = MobileCore.getInstance(SecurityService.class);

SecurityCheckResult result = securityService.check(SecurityCheckType.NO_DEBUGGER);
iOS
let security = AGSSecurity()
let result = security.check(IsDebuggerCheck())
Cordova
new SecurityService()
    .check(SecurityCheckType.notDebugMode)
    .then(result => {
        // Handle the security result metric
        // result: { id: string, name: string, passed: boolean }
    });
Xamarin
var securityService = MobileCore.GetService<SecurityService>();

SecurityCheckResult result = securityService.Check(SecurityChecks.NO_DEBUGGER);

Emulator Detection

Use this to detect if the app is being run on an emulator.

Android
SecurityService securityService = MobileCore.getInstance(SecurityService.class);

SecurityCheckResult result = securityService.check(SecurityCheckType.NOT_IN_EMULATOR);
iOS
let security = AGSSecurity()
let result = security.check(IsEmulatorCheck())
Cordova
new SecurityService()
    .check(SecurityCheckType.notEmulated)
    .then(result => {
        // Handle the security result metric
        // result: { id: string, name: string, passed: boolean }
    });
Xamarin
var securityService = MobileCore.GetService<SecurityService>();

SecurityCheckResult result = securityService.Check(SecurityChecks.NOT_IN_EMULATOR);

Device Lock Detection

Use this to detect if a device has a lock screen set (with pin, fingerprint, pattern…​).

Android
SecurityService securityService = MobileCore.getInstance(SecurityService.class);

SecurityCheckResult result = securityService.check(SecurityCheckType.SCREEN_LOCK_ENABLED);
iOS
let security = AGSSecurity()
let result = security.check(IsDeviceLockCheck())
Cordova
For iOS devices this check requires iOS 8 or above.
new SecurityService()
    .check(SecurityCheckType.hasDeviceLock)
    .then(result => {
        // Handle the security result metric
        // result: { id: string, name: string, passed: boolean }
    });
Xamarin
var securityService = MobileCore.GetService<SecurityService>();

SecurityCheckResult result = securityService.Check(SecurityChecks.SCREEN_LOCK_ENABLED);

App Data Backup Detection

Use this to detect whether the application’s data is configured to be synchronized across devices.

Android
SecurityService securityService = MobileCore.getInstance(SecurityService.class);

SecurityCheckResult result = securityService.check(SecurityCheckType.ALLOW_BACKUP_DISABLED);
iOS

This check is not available for iOS.

Cordova

This is not available for Cordova.

Xamarin
This check is available for Android only.
var securityService = MobileCore.GetService<SecurityService>();

SecurityCheckResult result = securityService.Check(SecurityChecks.ALLOW_BACKUP_DISABLED);

Device Encryption Detection

Use this to detect whether a devices filesystem is encrypted.

Android
SecurityService securityService = MobileCore.getInstance(SecurityService.class);

SecurityCheckResult result = securityService.check(SecurityCheckType.HAS_ENCRYPTION_ENABLED);
iOS

This check is not available for iOS.

Cordova

This is not available for Cordova.

Xamarin
This check is available for Android only.
var securityService = MobileCore.GetService<SecurityService>();

SecurityCheckResult result = securityService.Check(SecurityChecks.HAS_ENCRYPTION_ENABLED);

Invoking Multiple Self Defence Checks

Security Checks can be run in group, both synchronously and asynchronously.

Synchronously

Android
  1. Get a SyncCheckExecutor from SecurityService:

    SecurityService securityService = MobileCore.getInstance(SecurityService.class);
    SyncSecurityCheckExecutor syncCheckExecutor = securityService.getCheckExecutor();
  2. Add your checks and execute synchronously:

    Map<String, SecurityCheckResult> results = syncCheckExecutor
        .addCheck(SecurityCheckType.<check_type>)
        // Add more checks here
        .execute();
iOS

Invoke multiple checks using the checkMany function:

let checks = [IsDeviceLockCheck(), IsEmulatorCheck(), /** Add more checks here */ ]
let results = security.checkMany(checks)
SecurityCheckResult objects in the returning array stay in the same order they were provided.
Cordova

Executing multiple checks synchronously is not directly supported. Instead, it’s possible to use the await operator.

const results = await securityService.checkMany(
    SecurityCheckType.notRooted,
    SecurityCheckType.notEmulated,
    // Add more checks here
);
SecurityCheckResult objects in the returning array stay in the same order they were provided.
Xamarin
  1. Build a SyncSecurityCheckExecutor from SecurityService and execute:

    var securityService = MobileCore.GetService<SecurityService>();
    
    var checkExecutor = securityService.GetSyncExecutor()
                            .WithSecurityCheck(SecurityChecks.NOT_ROOTED)
                            .WithSecurityCheck(SecurityChecks.NO_DEVELOPER_MODE)
                            // Add more checks here
                            .Build()
    Dictionary<string, SecurityCheckResult> results = checkExecutor.Execute();

Asynchronously

Android
  1. Get an AsyncCheckExecutor from SecurityService:

    SecurityService securityService = MobileCore.getInstance(SecurityService.class);
    AsyncSecurityCheckExecutor asyncCheckExecutor = securityService.getAsyncCheckExecutor();
  2. Add your checks and execute synchronously:

    Map<String, Future<SecurityCheckResult>> results = asyncCheckExecutor
        .addCheck(SecurityCheckType.<check_type>)
        // Add more checks here
        .execute();
iOS

Executing multiple checks asynchronously is not supported at the moment for this platform.

Cordova

Invoke multiple checks using the checkMany method:

const checkResults = securityService.checkMany(
    SecurityCheckType.notRooted,
    SecurityCheckType.notEmulated,
    // Add more checks here
)
.then(results => {
    // Handle results
});
This method returns a Promise with an array containing all SecurityCheckResult objects in the same order they were provided.
Xamarin

Executing multiple checks asynchronously is not supported at the moment for this platform.

Additional Resources

Adding Custom Self Defence Checks

Besides the Provided Self Defence Checks it’s also possible to make use of your own custom checks. Follow the next steps depending on your platform to implement them:

Android
  1. Extend the AbstractSecurityCheck interface:

    class CustomSecurityCheck extends AbstractSecurityCheck {
    
        @Override
        protected boolean execute(@NonNull final Context context) {
            // Implement security check logic here
            return false;
        }
    
    }
  2. Instantiate it to execute it, using the instance of SecurityService:

    SecurityService securityService = MobileCore.getInstance(SecurityService.class);
    
    SecurityCheck customSecurityCheck = new CustomSecurityCheck();
    SecurityCheckResult result = securityService.check(customSecurityCheck);
iOS
  1. Implement the SecurityCheck interface:

    public class MyCustomCheck: SecurityCheck {
    
        public let name = "Custom Check"
    
        public init() {}
    
        public func check() -> SecurityCheckResult {
            // Implement security check logic here
            return nil
        }
    
    }
  2. Use the check function as usual:

    let security = AGSSecurity()
    let result = security.check(MyCustomCheck())
Cordova
  1. Implement the SecurityCheck interface:

    class CustomSecurityCheck implements SecurityCheck {
    
        get name(): string {
            return "My Custom Check";
        }
    
        public check(): Promise<SecurityCheckResult> {
            // Implement security check logic here
            return null;
        }
    
    }
  2. Instantiate it to execute it, using the instance of SecurityService:

    const securityService = new SecurityService();
    
    securityService.check(new CustomSecurityCheck())
        .then(result => {
            // Handle result
        });
Xamarin
  1. Implement the ISecurityCheck interface:

    class CustomSecurityCheck : ISecurityCheck
    {
        public string GetName()
        {
            return "Custom check";
        }
    
        public string GetId()
        {
            return typeof(CustomSecurityCheck).FullName;
        }
    
        public SecurityCheckResult Check()
        {
            // Implement security check logic here
            return null;
        }
    }
  2. Instantiate it to execute it, using the instance of SecurityService:

    var securityService = MobileCore.GetService<SecurityService>();
    
    SecurityCheckResult result = securityService.Check(new CustomSecurityCheck());

Reporting Self Defence Checks Results Via the Metrics Service

In order to report the results of Self Defence utilize this service in conjunction with the Metrics Service.

Android

Report individual checks via the checkAndSendMetric method:

MetricsService metricsService = MobileCore.getInstance(MetricsService.class);
SecurityService securityService = MobileCore.getInstance(SecurityService.class);

SecurityCheckResult result = securityService.checkAndSendMetric(SecurityCheckType.<check_type>, metricsService);

Or alternatively report multiple checks using a CheckExecutor:

MetricsService metricsService = mobileCore.getInstance(MetricsService.class);
Map<String, SecurityCheckResult> results = SecurityCheckExecutor.Builder.newSyncExecutor(this.getContext())
    .withSecurityCheck(SecurityCheckType.<check_type>)
    // Add other checks...
    .withMetricsService(metricsService)
    .build()
    .execute();
iOS

Report individual checks via the checkAndPublishMetric function:

let result = security.checkAndPublishMetric(IsDeviceLockCheck())

Or alternatively report multiple checks using the checkManyAndPublishMetric function:

let checks = [IsDeviceLockCheck(), IsEmulatorCheck(), /** Add more checks here */ ]
let results = security.checkManyAndPublishMetric(checks)
Cordova

Report individual checks via the checkAndPublishMetric method:

new SecurityService()
    .checkAndPublishMetric(SecurityCheckType.notRooted)
    .then(result => {
        // Handle the security result metric
        // result: { id: string, name: string, passed: boolean }
    });

Or alternatively report multiple checks using the checkManyAndPublishMetric method:

new SecurityService()
    .checkManyAndPublishMetric(
        SecurityCheckType.notRooted,
        SecurityCheckType.notEmulated,
        // Add more checks here
    )
    .then(results => {
        // Handle the security results array
    });
Xamarin

Self Defence reports are not yet available for Xamarin.

Certificate Pinning in Android Devices

Certificate pinning can be enabled in individual SDKs through the mobile-services.json file. Certificate pinning will only be enabled for services which are used directly by the SDKs. For other services SPKI pinning is used. Mobile services must have pinning configured separately. For more information on setting up certificate pinning for mobile services see the Android network security guide.

Generating Pinning Configuration

The AeroGear SDK gets its configuration from the https section of the mobile-services.json file in a project.

{
    "services":[],
    "https": {
        "certificatePins": [{
            "host": "example.sync.service",
            "certificateHash": "exampleHash"
        }]
    }
}

To include the https section in configuration when generating it using the Mobile CLI use the --include-cert-pins flag when retrieving a client configuration. By default, self-signed or invalid certs will not be permitted to be included in the certificate pinning configuration. To allow these to be included use the --insecure-skip-tls-verify flag.

$ ./mobile get clientconfig <client name> --include-cert-pins --insecure-skip-tls-verify

Using Pinning Configuration

If the https section is included in the mobile-services.json file then certificate pinning will automatically be enabled for mobile services.

Considerations

If the certificate authority of a service changes then the mobile-services.json file will need to be regenerated in order to retrieve the correct https configuration. The app will then need to be rebuilt and republished for the end users to consume. If this is not done then an app may become incapable of making network requests to other services.