Securing your mobile app
This guide does not address all mobile security topics. See the OWASP Mobile Security Project for an introduction to mobile security. AeroGear helps you achieve security:
-
Using the Mobile Security service - remotely disable specific app variants
-
Adding Device Checks to your mobile app - for example, disable app on rooted devices
Using the Mobile Security Service
-
You are running OpenShift with Mobile Services as described in Setting up AeroGear Mobile Services on OpenShift.
-
You have provisioned Mobile Developer Console as described in Provisioning Mobile Developer Console.
Setting Up the Mobile Security Service
Provisioning the Mobile Security Service
This section describes how to set up the Mobile Security Service.
-
You have logged into the OpenShift console and the Mobile Developer Console.
-
Log into the OpenShift console.
-
Create a new project or choose an existing project.
-
Click Add to Project and choose Browse Catalog from the options.
You can filter the catalog items to only show mobile specific items by clicking the Mobile tab.
-
Click Services and choose the Mobile Security service.
-
Follow the wizard for provisioning that service.
If prompted to Create a Binding, choose Do not bind at this time Once the wizard steps are completed, navigate to the Project Overview in OpenShift to see the newly provisioned service. Provisioning a service may take some time.
Binding a Mobile App with the Mobile Security Service
To use mobile services, you must represent your mobile app in Mobile Developer Console, and that app must be associated with the mobile service. This association is called binding and it is necessary for your mobile app to use that service.
This section describes how to set up the Mobile Security service.
-
You have created a Mobile App.
To bind a Mobile App with a mobile service:
-
Launch Mobile Developer Console.
-
Click on the Mobile App on the Overview screen.
-
Navigate to Mobile Services tab.
It is possible to bind a Mobile App with a mobile service in the OpenShift console, however such bindings are not valid for the purposes of this procedure. -
Click Bind to App for Mobile Security.
-
Fill out the binding parameters required by the Mobile Security Service.
The Mobile Security service will now be expandable, details about the service can be viewed.
Configuring your Development Environment for the Mobile Security Service
Downloading the Mobile Services Configuration File
-
Open your Mobile App in Mobile Developer Console.
-
Copy the
mobile-services.json
configuration to your clipboard. -
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. -
Follow the platform-specific instructions:
Setting up Mobile Security service SDK
Importing the libraries
-
Install the AeroGear Security package from NPM:
$ npm install @aerogear/security --save
-
Add the AeroGear Security plugin for Cordova:
$ cordova plugin add @aerogear/cordova-plugin-aerogear-security
-
Import and instantiate
SecurityService
to start using the SDK:const SecurityService = require("@aerogear/security"); const appSecurity = new SecurityService.AppSecurity(app.config);
Any new instantiation of SecurityService
returns the same instance.
Implementing the Mobile Security service in your mobile app
Call the appSecurity clientInit function to implement the App Security Service. Call this service on application initialization, for example:
appSecurity.clientInit()
.then(clientInit => {
/**
You can use clientInit.data.disabled boolean
to check if app has been disabled by admin.
The disabled message is returned if the app is
disabled at clientInit.data.disabledMessage
This contains a string with a disabled message
from the server set by the admin.
*/
}).catch(err => {
/**
You can handle errors connecting to the
mobile security service here. i.e. if the
client is offline that error will be caught
here and you can return a response at this
point
*/
});
Managing mobile apps using the Mobile Security Console
To access the Mobile Security Console:
-
Retrieve the console URL from the list of available services in the Mobile Developer Console (MDC).
-
Open the URL in a browser.
The console is only available after the Mobile Security Service has been provisioned.
The Mobile Security Console allows you to monitor mobile apps, deployed versions, and disable versions of those mobile apps.
Opening the console lists all applications. Click on an application to view deployed versions of that mobile app.
A deployed version is registered with the Mobile Security service when a version of the app is released, for example, 1.2.3, and that version of the app is run on a device at least once.
Below is a detailed description of each of these views and the information you can expect each to contain.
This view provides statistics and information about each deployed version of an application:
-
App Version: The version of the application.
-
Current Installs: Total number of current installed versions of this version of the application.
-
Launches: Total number of launches of this version of the application.
-
Last launched: The last time this application version was launched.
-
Disable on Startup: Whether this application version is disabled on startup.
-
Custom Disable Message: A custom message that is displayed when this version of the mobile app is disabled.
Enabling and disabling mobile app versions
To enable/disable one or more versions of the application:
-
Toggle the checkbox for that version in the Disable on Startup column.
-
Confirm these changes by clicking the Save button to persist these changes.
Navigating away from this screen with unsaved changes prompts you to save or discard these changes.
To disable all versions of an application:
-
Click the Disable App button.
Adding or updating a custom disabled message
To add or update a custom message for the version(s) of an application:
-
Enter the message in the text field for that version under the Custom Disable Message column.
-
Confirm these changes by clicking the Save button to persist these changes.
Navigating away from this screen with unsaved changes prompts you to save or discard these changes.
Implementing Device Checks in your mobile app
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. |
-
You understand Device Checks.
-
You have logged into the OpenShift console and the Mobile Developer Console.
-
You are developing an Ionic app, plain Cordova is not supported.
Device Checks Terminology
This section describes terminology that is associated with Device Checks.
- Root Access Detection (ROOT_ENABLED)
-
Use it to help prevent your app running in a device that has been rooted/jailbroken. A device is considered rooted if any of the following are true:
-
A custom key has been used to sign the kernel
-
The
su
binaries are present
-
DeviceChecks.ROOT_ENABLED
.
This function uses the Rootbeer library to check if root access is present on the device.
This check is not available for iOS.
This check is not available for Cordova.
This check is not available for Xamarin.
- Developer Mode Detection (DEVELOPER_MODE_ENABLED)
-
To detect if Developer Mode has been enabled on the device the
DeviceCheckType#DEVELOPER_MODE_ENABLED
function can be used. This function uses Android’s Settings class. - Debugger Detection (DEBUGGER_ENABLED)
-
To detect if an Android debugger is attached to the app the
DeviceCheckType#DEBUGGER_ENABLED
function can be used. This function uses Android’s Debug class. - Emulator Detection (IS_EMULATOR)
-
To detect if the app is being run on an emulator the
DeviceCheckType#IS_EMULATOR
function can be used. This function uses Android’s Build class. - Device Lock Detection (SCREEN_LOCK_ENABLED)
-
To detect if a device has a lock screen set (with pin, fingerprint, pattern) the
DeviceCheckType#SCREEN_LOCK_ENABLED
function can be used. This function uses Android’s KeyguardManager class. - App Data Backup Detection (BACKUP_ENABLED)
-
To detect whether the application’s data is configured to be synchronized across devices the
DeviceCheckType#BACKUP_ENABLED
function can be used. The allowBackup flag determines whether to allow the application to participate in the backup and restore infrastructure, which might be interesting to avoid depending on your app’s needs. - Device Encryption Detection (ENCRYPTION_ENABLED)
-
To detect whether the devices' filesystem is encrypted the
DeviceCheckType#ENCRYPTION_ENABLED
function can be used. This function uses Android’s DevicePolicyManager class.
Downloading the Configuration File
The mobile-services.json
file provides the information for your mobile app to communicate with services.
After you change any configuration in the Mobile Developer Console, it is important to update that file in your IDE.
-
The configuration of your Mobile App in Mobile Developer Console is up-to-date.
-
You have set up your mobile app development environment.
-
Open your Mobile App in Mobile Developer Console.
-
Copy the
mobile-services.json
configuration to your clipboard. -
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. -
Move
mobile-services.json
to the following location in your application project:
Setting up Device Checks service SDK
This guide will help you to set up the Device Checks service SDK in your App.
Importing the libraries
-
Add the following dependency in your app’s build.gradle:
dependencies { implementation 'org.aerogear:android-security:2.0.0' }
-
Get an instance of
SecurityService
to start using the SDK.SecurityService securityService = new SecurityService();
It is user responsibility to manage the SecurityService
lifecycle.
-
Add the dependency to your Podfile
target '[TARGET NAME]' do pod 'AGSSecurity', '2.0.0' end
-
Update the dependencies by running in your terminal
$ pod install
-
Import
AGSSecurity
and instantiate theSecurityService
to start using the SDKimport AGSSecurity let security = AGSSecurity()
Any subsequent call to AGSSecurity returns the same instance of the SecurityService
.
-
Install the AeroGear Security package from NPM
$ npm install @aerogear/security
-
Add the AeroGear Security plugin for Cordova:
$ cordova plugin add @aerogear/cordova-plugin-aerogear-security
-
Import and instantiate
SecurityService
to start using the SDK:const SecurityService = require("@aerogear/security"); const securityService = new SecurityService(app.metrics);
Any new instantiation of SecurityService
returns the same instance.
-
Install NuGet
-
Install the AeroGear Security package
$ dotnet add package AeroGear.Mobile.Security --version 2.0.1
-
Install the specific packages for Android:
$ dotnet add package AeroGear.Mobile.Security.Platform.Android --version 2.0.1
And for iOS:
$ dotnet add package AeroGear.Mobile.Security.Platform.iOS --version 2.0.1
-
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(); // ... }
-
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 note that Device Checks can be performed either individually or together.
Root Access Detection
Use this to help prevent your app running in a device that has been rooted/jailbroken.
SecurityService securityService = new SecurityService();
DeviceCheckResult result = securityService.check(DeviceCheckType.ROOT_ENABLED);
let security = AGSSecurity()
let result = security.check(JailbrokenDeviceCheck())
new SecurityService(app.metrics)
.check(DeviceCheckType.rootEnabled)
.then(result => {
// Handle the security result metric
// result: { id: string, name: string, passed: boolean }
});
Use ROOT_ENABLED
for Android:
var securityService = MobileCore.GetService<SecurityService>();
DeviceCheckResult result = securityService.Check(DeviceChecks.ROOT_ENABLED);
Use JAILBREAK_ENABLED
for iOS:
var securityService = MobileCore.GetService<SecurityService>();
DeviceCheckResult result = securityService.Check(DeviceChecks.JAILBREAK_ENABLED);
Developer Mode Detection
Use this to detect if Developer Mode has been enabled on the device.
SecurityService securityService = new SecurityService();
DeviceCheckResult result = securityService.check(DeviceCheckType.DEVELOPER_MODE_ENABLED);
This check is not available for iOS.
This check is not available for Cordova.
This check is available for Android only. |
var securityService = MobileCore.GetService<SecurityService>();
DeviceCheckResult result = securityService.Check(DeviceChecks.DEVELOPER_MODE_ENABLED);
Debugger Detection
Use this to detect if a debugger is attached to the app.
SecurityService securityService = new SecurityService();
DeviceCheckResult result = securityService.check(DeviceCheckType.DEBUGGER_ENABLED);
let security = AGSSecurity()
let result = security.check(DebuggerAttachedCheck())
new SecurityService(app.metrics)
.check(DeviceCheckType.debugModeEnabled)
.then(result => {
// Handle the security result metric
// result: { id: string, name: string, passed: boolean }
});
Use DEBUGGER_ENABLED
for Android:
var securityService = MobileCore.GetService<SecurityService>();
DeviceCheckResult result = securityService.Check(DeviceChecks.DEBUGGER_ENABLED);
Use DEBUGGER_ATTACHED
for iOS:
var securityService = MobileCore.GetService<SecurityService>();
DeviceCheckResult result = securityService.Check(DeviceChecks.DEBUGGER_ATTACHED);
Emulator Detection
Use this to detect if the app is being run on an emulator.
SecurityService securityService = new SecurityService();
DeviceCheckResult result = securityService.check(DeviceCheckType.IS_EMULATOR);
let security = AGSSecurity()
let result = security.check(IsEmulatorCheck())
new SecurityService(app.metrics)
.check(DeviceCheckType.isEmulator)
.then(result => {
// Handle the security result metric
// result: { id: string, name: string, passed: boolean }
});
var securityService = MobileCore.GetService<SecurityService>();
DeviceCheckResult result = securityService.Check(DeviceChecks.IS_EMULATOR);
Device Lock Detection
Use this to detect if a device has a lock screen set (with pin, fingerprint, pattern…).
SecurityService securityService = new SecurityService();
DeviceCheckResult result = securityService.check(DeviceCheckType.SCREEN_LOCK_ENABLED);
let security = AGSSecurity()
let result = security.check(DeviceLockEnabledCheck())
For iOS devices this check requires iOS 8 or above. |
new SecurityService(app.metrics)
.check(DeviceCheckType.screenLockEnabled)
.then(result => {
// Handle the security result metric
// result: { id: string, name: string, passed: boolean }
});
var securityService = MobileCore.GetService<SecurityService>();
DeviceCheckResult result = securityService.Check(DeviceChecks.SCREEN_LOCK_ENABLED);
App Data Backup Detection
Use this to detect whether the application’s data is configured to be synchronized across devices.
SecurityService securityService = new SecurityService();
DeviceCheckResult result = securityService.check(DeviceCheckType.BACKUP_ENABLED);
This check is not available for iOS.
This is not available for Cordova.
This check is available for Android only. |
var securityService = MobileCore.GetService<SecurityService>();
DeviceCheckResult result = securityService.Check(DeviceChecks.BACKUP_ENABLED);
Device Encryption Detection
Use this to detect whether a devices filesystem is encrypted.
SecurityService securityService = new SecurityService();
DeviceCheckResult result = securityService.check(DeviceCheckType.ENCRYPTION_ENABLED);
This check is not available for iOS.
This is not available for Cordova.
This check is available for Android only. |
var securityService = MobileCore.GetService<SecurityService>();
DeviceCheckResult result = securityService.Check(DeviceChecks.ENCRYPTION_ENABLED);
Invoking Multiple Device Checks
Device Checks can be run in group, both synchronously and asynchronously.
Synchronously
-
Get a
SyncCheckExecutor
fromSecurityService
:SecurityService securityService = new SecurityService(); SyncDeviceCheckExecutor syncCheckExecutor = securityService.getCheckExecutor();
-
Add your checks and execute synchronously:
Map<String, DeviceCheckResult> results = syncCheckExecutor .addCheck(DeviceCheckType.<check_type>) // Add more checks here .execute();
Invoke multiple checks using the checkMany
function:
let checks = [DeviceLockEnabledCheck(), IsEmulatorCheck(), /** Add more checks here */ ]
let results = security.checkMany(checks)
DeviceCheckResult objects in the returning array stay in the same order they were provided.
|
Executing multiple checks synchronously is not directly supported. Instead, it’s possible to use the await operator.
const results = await securityService.checkMany(
DeviceCheckType.rootEnabled,
DeviceCheckType.isEmulator,
// Add more checks here
);
DeviceCheckResult objects in the returning array stay in the same order they were provided.
|
-
Build a
SyncDeviceCheckExecutor
fromSecurityService
and execute:var securityService = MobileCore.GetService<SecurityService>(); var checkExecutor = securityService.GetSyncExecutor() .WithDeviceCheck(DeviceChecks.ROOT_ENABLED) .WithDeviceCheck(DeviceChecks.DEVELOPER_MODE_ENABLED) // Add more checks here .Build() Dictionary<string, DeviceCheckResult> results = checkExecutor.Execute();
Asynchronously
-
Get an
AsyncCheckExecutor
fromSecurityService
:SecurityService securityService = new SecurityService(); AsyncDeviceCheckExecutor asyncCheckExecutor = securityService.getAsyncCheckExecutor();
-
Add your checks and execute synchronously:
Map<String, Future<DeviceCheckResult>> results = asyncCheckExecutor .addCheck(DeviceCheckType.<check_type>) // Add more checks here .execute();
Executing multiple checks asynchronously is not supported at the moment for this platform.
Invoke multiple checks using the checkMany
method:
const checkResults = securityService.checkMany(
DeviceCheckType.rootEnabled,
DevoceCheckType.isEmulator,
// Add more checks here
)
.then(results => {
// Handle results
});
This method returns a Promise with an array containing all DeviceCheckResult objects in the same order they were provided.
|
Executing multiple checks asynchronously is not supported at the moment for this platform.
Additional Resources
Adding Custom Device Checks
It is possible to make use of your own custom checks. Follow the next steps depending on your platform to implement them:
-
Extend the
AbstractDeviceCheck
interface:class CustomDeviceCheck extends AbstractDeviceCheck { @Override protected boolean execute(@NonNull final Context context) { // Implement security check logic here return false; } }
-
Instantiate it to execute it, using the instance of
SecurityService
:SecurityService securityService = new SecurityService(); DeviceCheck customDeviceCheck = new CustomDeviceCheck(); DeviceCheckResult result = securityService.check(customDeviceCheck);
-
Implement the
DeviceCheck
interface:public class MyCustomCheck: DeviceCheck { public let name = "Custom Check" public init() {} public func check() -> DeviceCheckResult { // Implement security check logic here return nil } }
-
Use the
check
function as usual:let security = AGSSecurity() let result = security.check(MyCustomCheck())
-
Implement the
DeviceCheck
interface:class CustomDeviceCheck implements DeviceCheck { get name(): string { return "My Custom Check"; } public check(): Promise<DeviceCheckResult> { // Implement device check logic here return null; } }
-
Instantiate it to execute it, using the instance of
SecurityService
:const securityService = new SecurityService(app.metrics); securityService.check(new CustomDeviceCheck()) .then(result => { // Handle result });
-
Implement the
IDeviceCheck
interface:class CustomDeviceCheck : IDeviceCheck { public string GetName() { return "Custom check"; } public string GetId() { return typeof(CustomDeviceCheck).FullName; } public DeviceCheckResult Check() { // Implement security check logic here return null; } }
-
Instantiate it to execute it, using the instance of
SecurityService
:var securityService = MobileCore.GetService<SecurityService>(); DeviceCheckResult result = securityService.Check(new CustomDeviceCheck());
Reporting Device Checks Results Via the Metrics Service
In order to report the results of Device Checks utilize this service in conjunction with the Mobile Metrics service.
Report individual checks via the checkAndSendMetric
method:
MetricsService metricsService = MobileCore.getInstance(MetricsService.class);
SecurityService securityService = new SecurityService();
DeviceCheckResult result = securityService.checkAndSendMetric(DeviceCheckType.<check_type>, metricsService);
Or alternatively report multiple checks using a CheckExecutor
:
MetricsService metricsService = mobileCore.getInstance(MetricsService.class);
Map<String, DeviceCheckResult> results = DeviceCheckExecutor.Builder.newSyncExecutor(this.getContext())
.withDeviceCheck(DeviceCheckType.<check_type>)
// Add other checks...
.withMetricsService(metricsService)
.build()
.execute();
Report individual checks via the checkAndPublishMetric
function:
let result = security.checkAndPublishMetric(DeviceLockEnabledCheck())
Or alternatively report multiple checks using the checkManyAndPublishMetric
function:
let checks = [DeviceLockEnabledCheck(), IsEmulatorCheck(), /** Add more checks here */ ]
let results = security.checkManyAndPublishMetric(checks)
Report individual checks via the checkAndPublishMetric
method:
new SecurityService(app.metrics)
.checkAndPublishMetric(DeviceCheckType.rootEnabled)
.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(app.metrics)
.checkManyAndPublishMetric(
DeviceCheckType.rootEnabled,
DeviceCheckType.isEmulator,
// Add more checks here
)
.then(results => {
// Handle the security results array
});
Report individual checks:
var securityService = MobileCore.GetService<SecurityService>();
var metricsService = MobileCore.GetService<MetricsService>();
DeviceCheckResult result = securityService.Check(DeviceChecks.ROOT_ENABLED, metricsService);
Or alternatively report multiple checks using a CheckExecutor
:
var securityService = MobileCore.GetService<SecurityService>();
var metricsService = MobileCore.GetService<MetricsService>();
var checkExecutor = securityService.GetSyncExecutor()
.WithDeviceCheck(DeviceChecks.ROOT_ENABLED)
.WithDeviceCheck(DeviceChecks.DEVELOPER_MODE_ENABLED)
.WithMetricsService(metricsService)
// Add more checks here
.Build()
Dictionary<string, DeviceCheckResult> results = checkExecutor.Execute();
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.