This is an old version (v2.6). Please click here for the latest (v3.0).
Table of Contents

Approov User Manual

Getting Started With Approov

This documentation provides a detailed reference manual for using Approov. If you are new to Approov then you might find it easier to start with the Quickstart Integrations for the frontend and backend. You can then return to this manual as needed for detailed usage guidance.

Once you have installed the Approov CLI Tool there are a few more steps to get your Approov integrated app running. These are set out in roughly the expected order over the next few sections of this manual:

  1. Familiarize yourself with Account Access Roles in the Approov CLI
  2. Integrate the SDK into your Android or iOS app
  3. Get the SDK Configuration
  4. Write the code to initialize the SDK in your app
  5. Add the API domain(s) to be protected by Approov
  6. Integrate some code in your app to fetch Approov tokens and send them in API requests
  7. Build your app and register it with the Approov cloud service
  8. Modify your API backend to check the Approov tokens

After following these steps you should have a working Approov integration, although there are of course other features you can try. In particular, we strongly recommend that you configure pins and implement pinning in the app.

Other aspects you might want to try are:

  • Update your Security Policy to change the conditions under which an app will be given a valid Approov token.
  • Learn how to Manage Devices to apply custom policies to specific devices (useful for enabling debug on your development devices).
  • Learn how to Manage Key Sets to managing additional keys for signing or encrypting Approov tokens, and to allow access to a wide range of JWT algoriths beyond the default HS256 signing method.
  • Understand User Management so you can add and remove access for others to your Approov account.
  • Employ Automated Approov CLI Usage to enable integration of Approov with Continuous Integration (CI) systems.
  • Use the Metrics Graphs to see live and accumulated metrics of devices using your account and any reasons for devices being rejected and not being provided with valid Approov tokens. You can also see your billing usage which is based on the total number of unique devices using your account each month.
  • Use Service Monitoring emails to receive monthly (or daily) summaries of your Approov usage. You can also manage the API domains to be continuously monitored to ensure they are accessible and that the pins match those added to your account.
  • Investigate advanced features, such as Token Binding, Offline Security Mode, Apple DeviceCheck Integration, Google SafetyNet Integration, Device Filters, Message Signing and Android Automated Launch Detection.

You can reach the support portal at https://approov.zendesk.com. Sign up for an account or use an existing Google account. This portal is reserved for technical enquiries only.

You can reach your subscription the portal at https://approov.chargebeeportal.com. If you are a new account holder, you can request a new sign-up link at the bottom of the portal page, otherwise use your credentials to log in. The portal allows you to change your subscription plan, update your payment details, terminate your subscription, etc. For further sales-related enquiries, please contact sales@approov.io

Account Access Roles

When you initialize access to your Approov account through the CLI a number of different access roles may have been installed. Typically these will have been dev and admin. The dev role is automatically made active on installation.

Most operations can be carried out using the dev role, but certain more security sensitive operations are reserved so that they can only be executed when you have assumed an admin role. To assume the admin role you can type:

$ eval `approov role admin`

When you issue the next approov CLI command you may be invited to provide the password. You should only assume the admin role for the period that you need it and then you should assume the dev role again. Note that on Windows you must use the form set APPROOV_ROLE=admin:myaccount where myaccount is the name of your Approov account.

To see a list of all the roles available use:

$ approov role
available role commands:
  eval `approov role admin`
  eval `approov role dev`
  approov role .

This lists all of the user roles you have installed on your machine, and the command required to assume that role. The command you actually need to issue is eval which evaluates the return from the approov role command itself. This is a string for exporting the APPROOV_ROLE environment variable, which selects the active role. This ensures that each individual shell, which can have a different APPROOV_ROLE values, may have a different role selected. This prevents any unwanted interaction between terminal shells when you select a different role as the selection is only for the current shell. Any newly created shell will default to using the dev role, if that is available.

Note that on the Windows platform the role commands look slightly different, such as the following:

$ approov role
available role commands:
  set APPROOV_ROLE=admin:myaccount
  set APPROOV_ROLE=dev:myaccount
  approov role .

Thus you must issue these set commands directly to change the current role.

User role sessions are controlled by the Approov cloud. This means that if you have initialized the same access on multiple machines, operations that end a session on one machine will impact all other machines using the same user roles.

If you explicitly select a role again, after you have provided a password, then this ensures that the session is refreshed to be a full hour long. You can use this if you wish to perform some scripted operations using the Approov CLI and you do not want the session to time out during this time. You can use the form approov role . to extend the session for the currently active role without have to explicitly select it.

It is possible to see which role is selected at any time as follows:

$ approov whoami
admin: https://admin-something.approovr.io
configuration: /home/me/.approov
account: myaccount
role: dev
ID: dev-1016
name: my name
email: me@mydomain.com
expiry: 2020-12-04 14:00:30

The shows both the role and account, as well as other relevant information.

Note also that it is also possible to initialize access to multiple different Approov accounts, e.g.:

$ approov role
available role commands:
  eval `approov role admin myaccount`
  eval `approov role dev myaccount`
  eval `approov role dev myotheraccount`
  approov role .

In this case an additional parameter is always required to specify the account as well as the role required.

It is not possible to remove roles once they have been initialized on machine. If the access provided expires or is revoked then the role will remain but you will no longer be able to use it. If you execute an approov init with revised access then that will replace any expired or revoked user role. The initialized roles are stored in a .approov file in your home directory. You can completely remove this file, but then you will need to reinitialize access via the access recovery flow.

Passwords

Password protection improves your security posture and dramatically reduces the risk of your account being compromised. Approov access information is held in the .approov configuration in your home directory and this will only have access permissions for your user identity. However, if your machine account is compromised then so could access to your Approov account. This could allow an attacker to generate valid Approov tokens or prevent your apps from doing so. Password protection of Approov user roles prevents this. Sessions time out after a maximum of one hour and after this time the password is required again for access. The password itself is never stored by the Approov CLI on your machine.

Communication between the Approov CLI and the Approov cloud service is always conducted using TLS, but its security is subject to the certificate trust store installed on your local machine. Ordinarily if this were to be compromised then it would be possible for a Man-in-the-Middle (MITM) attacker to intercept, modify and then spoof requests to the Approov cloud service. The password mechanism also provides protection from such compromises, as it provides an additional level of message integrity over and above TLS. It employs asymmetrically encrypted integrity tokens with a proof of password possession protocol to transmit this information, ensuring that an attacker cannot spoof these integrity tokens without knowledge of the password.

If a CLI command is issued that uses a password protected role, then the user will be invited to provide the password before they can continue. Once the password is correctly entered this initiates an active session that lasts for one hour. During that time it is not necessary to enter the password again in order to issue CLI commands. The current session information is stored in a .approov file in your home directory.

Different users should not share user roles, you should add new user roles as required, allowing each user to set their own passwords.

If you wish to reset the password for a user role then first select the role. Then use the following command:

approov password -sendCode
password reset code for dev role in account myaccount sent to me@mydomain.com
use the command "approov password -setWithCode <emailed-code>" to set the password

This sends the reset information to the email associated with the user role. The email provides a long base64url encoded reset code string that is valid for at least 30 minutes. This long code is actually used to encrypt the new password information sent to the Approov cloud. This ensures that no MITM can possibly intercept the password information, or set their own passwords, without access to the code in the email.

You can then set the password as follows (use the code received in your email, not the one listed below):

$ approov password -setWithCode Gbf4erRmu3lrWAGAIW60kMXlkSYK1jJmtqRicMFAZCg
setting password for dev role in account myaccount
enter password:
confirm password:
new password set for dev role in account myaccount

You will be asked to enter a password (of at least six characters) and then re-enter for confirmation. It is not echoed to the terminal.

After a password has been set, you will be asked to enter it the next time you assume the role, or when the session has timed out with the role active and you issue another command.

Note it is also possible, although not recommended, to remove the need to use a password for a paricular user role. Go through the procedure of obtaining a reset code and then:

$ approov password -clearWithCode Gbf4erRmu3lrWAGAIW60kMXlkSYK1jJmtqRicMFAZCg
WARNING: we recommend that you protect your access using passwords. If you wish to continue then please enter YES and return: YES
password cleared for dev role in account myaccount

Account Access Recovery

If you are installing the Approov CLI onto another machine, or if your Approov configuration is somehow lost, then you will need to use the recovery flow. This will send a new onboarding email to your email address with a refreshed onboarding code allowing you to run approov init again. Note that, for security reasons, you must have a record of the recovery PIN that was provided during the original initialization. This is to prevent an attacker gaining access to your Approov account if they are able to gain access to your email account.

The recovery command is included in the original onboarding email, and will be similar to the following:

$ approov init myaccount me@mydomain.com aprv2-svpc.critical.blue
you must provide the recovery PIN that you were given when you first initialized Approov access for this account
enter PIN and return: 123456
onboarding email for account myaccount to me@mydomain.com will be sent if this combination is valid (wait 5 minutes before retrying)

You must specify the account name and the email address to which the access was issued. You will also be asked for the recovery PIN. If all this information is correct then you will receive an Approov Onboarding email. This email will only ever be sent to the address to which the role was assigned (you can’t use this to recover access if your email address has changed). No indication is given if the provided information is incorrect, the command will just silently fail. Note that, if you think some of the information is incorrect on one attempt, you must wait 5 minutes before retrying due to the protections in place agaist the brute forcing of the PIN value.

Migrating to Account Access Roles

If you signed up to use an earlier version of Approov then you will have been issued with management tokens, rather than an onboarding code. This will have been set in an APPROOV_MANAGEMENT_TOKEN environment variable. Moreover your management tokens will not be protected using a password. It is possible to import your existing management tokens to use the new role based approach as follows:

$ approov init mydev.tok
management token dev-6805 for account myaccount has been imported
password reset code sent to me@mydomain.com
select this role and then use the command "approov password -setWithCode <emailed-code>" to set a password for the management token

This imports the management token saved in the file mydev.tok. You should now remove the environment variable APPROOV_MANAGEMENT_TOKEN.

An email is automatically sent that allows you to set a password if you wish. Otherwise the email can be ignored. If you wish to set the password then do the following:

$ eval `approov role dev`
$ approov password -setWithCode Gbf4erRmu3lrWAGAIW60kMXlkSYK1jJmtqRicMFAZCg
setting password for dev role in account myaccount
enter password:
confirm password:
new password set for dev role in account myaccount

You will probably also want to import your myadmin.tok management token as well. Note that the password for this is set seperately, although of course you may choose to use the same password.

Approov Architecture

This describes the overall architecture of Approov and familiarizes you with the key concepts required to understand the steps in the Approov integration.

Key Components

The key components of Approov are detailed in the following diagram:

Overall Architecture

The steps required to obtain an Approov token are as follows:

  1. You will be able to administer the properties of your account using the approov command line tool and Approov account access you were issued upon sign up. A key aspect of this administration is the registration of new apps that are to be released to the app store. The approov tool analyzes the app (in either .apk, .aab or .ipa format) and adds its signature to a database in the Approov cloud service for your account. The particular build of the app then becomes recognized as being official, allowing valid Approov tokens to be generated for calls from that app.
  2. Your app itself must make a call to either the fetchApproovToken or fetchApproovTokenAndWait methods in the Approov SDK that must be integrated into your app. Note that these calls must only be made after having initialized the Approov SDK. If this is the first call to obtain an Approov token, then it will initiate an integrity measurement process inside the SDK that requires communication with the Approov cloud service. Once an Approov token has been obtained it is cached by the SDK for up to 5 minutes so that subsequent fetch calls do not require additional network communication.
  3. The integrity check process requires the SDK and the Approov cloud service to work together. The SDK analyzes the runtime environment of the app and the authenticity of the app that is being measured. These checks are implemented in hardened code and communications are protected both by TLS and also by a secondary level of request integrity signing. The Approov cloud service performs analysis on the data provided by the SDK and makes a decision based on this and the security policy criteria you set for your account. If the criteria are met then the Approov cloud provides a short lived token signed with a symmetric secret allocated randomly during your account sign up. If the criteria are not met then a token is still issued, but it is not signed with the correct secret. Options are also available to use other secrets or other signing algorithms, including those with asymmetric keys.
  4. The obtained Approov token should be transmitted with a backend API request. We recommend you add the token as an additional header, such as Approov-Token, but the approach will depend on your particular API. It is important that all communications made by these APIs are pinned so that no Man-in-the-Middle (MitM) interception is possible that could make a copy of the short lived token. Pinning TLS connections is good security hygiene anyway, as it prevents customer data being intercepted in the same way.
  5. Your backend API is able to check the validity of the Approov token by checking it has been correctly signed with the symmetric secret. If it is, then you know that the API request is really coming from an official registered version of your app; it is not being spoofed by some other entity. Moreover, a valid Approov token also indicates that the checks on the runtime environment have passed, as controlled by the security policy you have set in your account. Since the shared symmetric key is never put inside the app, an attacker cannot reverse engineer it in order to create their own signed Approov tokens without going through the integrity measurement process.

Detection Capabilities

Approov is able determine various properties of the app and the environment in which it is running. The individual detections are mapped to individual property flags that are determined each time an Approov token is fetched. It is possible to set security policies that determine, at a fine grain level, whether a given detection should result in a valid Approov token being issued or not. The summary below may change at any time as new threats are recognized, but we will endeavor to keep this table as up to date as we can.

Type Description
Authenticity Analysis of the app to ensure it is one that has been officially registered. Failure may indicate that a fake or tampered app is being used, or one where its registration has been revoked.
Automation Detections of the app being automated in some way. For a production app this is a strong indicator of automation that may be associated with some nefarious use of the app. Basic detection is in place for Appium iOS and monkeyrunner on Android.
Banning Mechanisms are provided to ban particular devices so that they no longer receive valid Approov tokens. Yes
Cloning Android app cloning is detected, which allows an app to be effectively installed inside another app, typically to allow multiple accounts on the same device. Permitting apps to run this way may have significant implications for the users security and privacy. Approov detects a multitude of these cloning apps, a popular example being Parallel Space. No
Debugging Various levels of detection are used to determine if the app is running in a debug environment. Yes
DeviceCheck Approov provides an optional integration with Apple's DeviceCheck capability. Various propeties can be extracted from the results of this and used to determine device rejection. This may also be used to provide permanent banning of specific devices. Yes
Emulation Detection that the app is running on an Android emulator or iOS simulator. For Android, if the SDK is running on x86, then it is more likely to be an emulator, so only an internal whitelist of known real 32-bit x86 devices are allowed through. Currently all 64-bit Android x86 devices are categorized as emulators. Yes
Frameworks Detections for various framework and modding environments. For iOS specifically Cycript and Cydia are detected. Android specifically detects the Xposed framework. The Frida framework is detected on both Android and iOS, with protections to prevent attachment to the app while it is running. Yes
Filtering Capabilities are provided for filtering devices based on various characteristics. This may be for information only or it may be used to reject or permanently ban certain devices. No
Jailbreaking Detection that the iOS device the app is running on has been jailbroken. Yes
Rooting Detection that the Android device the app is running on has been rooted. This includes detection of the Magisk root manager, even when it is being actively cloaked. Yes
SafetyNet Approov provides an optional integration with Google's SafetyNet. Various propeties can be extracted from the results of this and used to determine device rejection. No
Spoofing Approov provides integrity guarantees for the the data transfer between the protected core of the SDK and the Approov cloud service. Any tampering is detected and causes failing Approov tokens to be issued. Yes
Tampering Various checks are performed to ensure the runtime integrity of the app. The overall app memory layout is also monitored looking for suspicious changes or configurations indicating that the app is being monitored or attacked. Yes
Unpinning Detection that pinned connections between the app and the backend API are being compromised. Approov can perform continuous pinning testing and there is detection of certain frameworks designed to compromise the integrity of pinning. Yes

Security Rules Updates

The Approov SDK is able to execute security analysis rules that are supplied dynamically by the Approov cloud service as illustrated below:

You may set your security policy and Approov researchers are continually updating the set of rules and security signatures that are being detected to indicate malicious intent inside the app’s runtime environment. When the first Approov token fetch is made in the app, the latest set of security rules are transmitted from the Approov cloud to the SDK. These rules specify the data to be gathered by the SDK and the checks to perform to identify particular threat signatures. The security rules are automatically updated for running apps if they are changed on the server.

Whenever an Approov token fetch is performed, a predetermined subset of the gathered data and the results of signature analysis are transmitted securely to the Approov cloud. Data analysis is then performed before determining if the particular app instance should be issued with a valid or an invalid Approov token.

This mechanism is also used by Approov researchers to gather intelligence on specific devices that are associated with malicious behaviour. It enables a highly reactive security stance without the requirement for SDKs within apps to be updated.

Cloud Server Redundancy

To enable a highly reliable Approov service, the backend is implemented in two different cloud service providers, as illustrated below:

When an Approov token fetch is requested, the initial transmission is sent to a the primary token service hosted in the AWS cloud. This primary service has multiple frontend servers deployed across the availability zones of a region and is setup to automatically scale with the service load. The particular geographic data center utilized is allocated upon sign up. Some accounts may also have support in multiple different geographic data centers to lower latencies in different parts of the world and to offer further enhanced redundancy.

If communication cannot be established with the primary service (or errors are continually returned) then the SDK attempts to make contact with the secondary (aka failover) system. This is available on a different domain name using a different TLD (Top Level Domain) to further enhance redundancy. The secondary failover system is implemented in Google Cloud to provide complete isolation from large scale failures that may occur in AWS. The failover system only provides a subset of the full analysis capability of the primary system, but it will ensure your apps should continue to receive valid Approov tokens in the event of a catastrophic primary system failure.

The failover system only serves Approov tokens if it is enabled. It continually checks the primary system on a minute-by-minute basis and automatically enables itself if a primary failure is detected, with no need for any manual intervention in the switch over process.

Android SDK Integration

This section shows you how to get the Android Approov SDK and integrate it into your project in Android Studio.

Getting the Android SDK

The Android Approov SDK can be downloaded using the approov command line tool. Use the following command to download the latest SDK package:

$ approov sdk -getLibrary approov_sdk.aar
Android SDK library 2.5.0(2974) written to approov_sdk.aar

This writes the latest available SDK package to the approov_sdk.aar file (or any path that you specify).

You will be informed if a new SDK version is available when you register an app that contains an older version. If this happens you should consider upgrading using this command, which will always provide the latest version.

In some cases you may have been directed to use a specific version of the SDK with a particular numeric identifier. You can select it as follows, 2772 in this example:

$ approov sdk -getLibrary approov_sdk.aar -libraryID 2772
Android SDK library 2.4.0(2772) written to approov_sdk.aar

Importing the SDK into Android Studio

The Approov SDK minimum requirement is Android 5 (API level 21). You cannot use Approov in apps that support versions older than this.

The Approov SDK can be added to an existing app project in Android Studio using the following steps (instructions are accurate for Android Studio 4.1.1 and above):

  1. Make sure the Project View is open (if it is not, click on Project located on the left hand side near the top).
  2. Depending on your Project View’s Group Tabs setting (accessible by right-clicking on Project), the Project View’s tabs are either visible side-by-side, or grouped together in a drop-down menu
  3. Select the Android tab (at the top of the Project View).
  4. Right-click on the app folder in the Android tab and select NewModule:

    Android Studio: Add new module

  5. Select the Import .JAR/.AAR Package option and click on Next.

    Android Studio: Import AAR

  6. Enter the path for your Approov SDK .aar that you previously downloaded into the File name field (or navigate to the .aar and click OK). The Subproject name field will be populated with the .aar name you can also choose a different sub-project name if desired.

    Android Studio: Import AAR Name

  7. Click Finish. You may be asked about adding the fiels to git. The new subproject folder should appear in the Android tab.

  8. Right-click on the app folder in the Android tab and select Open Module Settings.

  9. Ensure that the app module is selected in the sidebar on the bottom left.

  10. Click on the Dependencies tab and click on the green + button (labeled Add) in the top right corner.

  11. Select 3 Module Dependency.

    Android Studio: Select module dependency

  12. Select the Approov SDK module that you just imported, click OK and then click OK again to close the window.

    Android Studio: Select the Approov SDK module

  13. A Gradle sync will then run.

Once you have successfully completed these steps you are ready to start making use of the Approov SDK. The SDK methods are available by importing the package:

import com.criticalblue.approovsdk.Approov;

The Approov SDK uses the OkHttp stack for making its requests, so the following dependency must be added to your Gradle file:

implementation 'com.squareup.okhttp3:okhttp:4.9.0'

Please also add the following code to your gradle file:

android {
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

The following app permissions need to be available in the manifest to use the Approov SDK:

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />

Logging output from the Approov SDK can be seen under the Approov tag in logcat. Normally the SDK is silent except during initialization or if there is a problem with connectivity. Approov support may require this logging to answer any issue you may raise.

The initial logging on startup will be similar to the following:

2019-05-29 11:53:06.637 4997-4997/? I/Approov: test-account, com.criticalblue.demo, 2.5.0(2974), h4gubfCFzJu81j/U2BJsdg==

It provides information about the account, app, SDK and the device ID.

We suggest you target your app at an API level below Android 11 (API level 30). This is because some aspects of the Approov SDK environment analysis rely on PackageManager visibility that have been restricted from this target version.

Android Obfuscation

Note that since the Approov SDK is already obfuscated with Proguard so you should not attempt to obfuscate it again (with Proguard or R8) as this will cause it to stop working. Add the following exemption to your proguard-rules.pro:

-keep class com.criticalblue.approovsdk.** {*;}

Use on Emulator

We recommend using a physical device for testing your apps. However, you can use an Android Virtual Device (AVD) in Android Studio. Normally the Approov service will not generate a valid Approov token when running in the emulator and will indicate a rejection wih the emulator property. The only way to obtain a valid Approov token on an emulator is to whitelist it. This requires extracting the device ID. We suggest that the approov device -add latest is the easiest method when first trying Approov.

iOS SDK Integration

This section shows you how to get the iOS Approov SDK and integrate it into your project in Xcode.

Getting the iOS SDK as an XCFramework

The iOS Approov SDK can be downloaded using the approov command line tool. By default the SDK is provided as a dynamic XCFramework to allow usage with both physical devices and simulators. Use the following command to download the latest SDK package:

$ approov sdk -getLibrary Approov.xcframework
iOS SDK library 2.6.0(5647) written to Approov.xcframework

This writes the SDK into the directory Approov.xcframework (or any path that is specified). Ensure that this is empty before you perform this operation. Note that the raw iOS package is quite large so it may take some seconds to download depending upon your connection speed. Download progress is shown.

You will be informed if a new SDK version is available when you register an app that contains an older version. If this happens you should consider upgrading using this command, which will always provide the latest version.

It is also possible to obtain a bitcode version of the SDK library. We recommend that you use the native version unless you have to use bitcode for other reasons in your release process. The bitcode version can be obtained as follows:

$ approov sdk -getLibrary Approov.xcframework -bitcode
iOS-bitcode SDK library 2.6.0(5647) written to Approov.xcframework

Obtaining the bitcode version of an SDK automatically updates some aspects of the security settings for your account. So, if you intend to use a bitcode SDK it is important to download it using the Approov CLI to ensure these settings changes are made.

In some cases you may have been directed to use a specific version of the SDK with a particular numeric identifier. You can select it as follows, 5643 in this example:

$ approov sdk -getLibrary Approov.xcframework -libraryID 5643
iOS SDK library 2.6.0(5643) written to Approov.xcframework

Obtaining the SDK as a .xcframework is only supported from version 2.6.0.

Importing the SDK into Xcode

The Approov SDK minimum requirement is iOS 10. You cannot use Approov in apps that support versions older than this.

The Approov framework can be added to an existing app Xcode project using the following steps:

  1. In the Xcode project editor, select the target to which you want to add the Approov SDK framework.
  2. Select the General tab.
  3. Select the + (plus) icon under the Embedded Binaries section.
  4. Select Add Other... in the file dialog and browse to the Approov.xcframework obtained using the approov command line tool.
  5. Select Open in the file dialog.
  6. Ensure the Copy items if needed destination option is checked, then select Finish.

    xCode: Add Approov SDK

  7. The Approov.xcframework entry should now be present in the Embedded Binaries and Linked Frameworks and Libraries sections, indicating that this will be included and linked with your app.

    xCode: Verify Approov SDK

To access the Approov framework in source code, the public header must be imported. This can be achieved by adding the following to the top of your source or header files:


import Approov

import <Approov/Approov.h>

Use on Simulator

We recommend using a physical device for testing your apps, however, the simulator architectures are provided for you to use when this is not possible. Normally, the Approov service will not generate a valid Approov token for a simulator device. The Approov service will indicate a rejection wih the ios-simulator property. The only way to obtain a valid Approov token on a simulator is to whitelist it. This requires extracting the device ID. We suggest that the approov device -add latest is the easiest method when first trying Approov. Please note, using the command line to install or remove applications on the simulator may produce a different device ID. This is also the case when the simulator is reset which erases all settings and applications.

Please note, if targetting a simulator device and using xcframework SDK, Approov does not currently provide a full set of possible CPU architectures. There is no support for i386 architecture. We are planning on releasing support for arm64 simulator in early 2021. Since Xcode might try building all the simulator architectures by default this will produce an error. You can disable any unavailable architecture in your target build options, Architectures section as follows:

XCode: Disable architectures

Getting the iOS SDK as a Framework

It is also possible to obtain the SDK in the classic .framework format as follows:

$ approov sdk -getLibrary Approov.framework
iOS device SDK library 2.6.0(5647) written to Approov.framework

This writes the SDK into the directory Approov.framework (or any path that is specified). Ensure that this is empty before you perform this operation. Note that the raw iOS package is quite large (of the order of 10MB) so it may take some seconds to download depending upon your connection speed. Download progress is shown.

By default the SDK provided is only suitable for running on physical devices. You can use the -simulator option to obtain a different SDK that only includes simulator archiectures. It is also possible to use the -bitcode option to obtain bitcode enabled versions of the SDK for either devices or simulators.

Note that it is also possible to obtain an SDK in the legacy .zip format by using this extension. This provides the SDK in a zipped file of Approov.framework.

If you download a version of the SDK prior to 2.6.0 using this method then it will contain architectures for both physical devices and simulators. This is not compatible with Xcode version 12.3 or later. You must remove the simulator architectures using lipo -remove x86_64 Approov.framework/Approov -o Approov.framework/Approov and lipo -remove i386 Approov.framework/Approov -o Approov.framework/Approov prior to importing into Xcode.

Logging

Logging is output by the iOS SDK into the document directory for the app in a file named Approov.log. The SDK only generates logs during initialization or if there is a connectivity issue with the SDK. You may be asked to supply this file to Approov support if you log a support request and we are unable to diagnose the issue by interrogating our servers. Note that, you may also need to look at this file to obtain the device ID.

In order to access the log file produced by Approov, the property label Application supports iTunes file sharing has to be added to the Information property list in Xcode and the Boolean value has to be set to Yes. If modifying the Information property list with an external editor, the equivalent property key is UIFileSharingEnabled and the value must be set to true. It is then possible to use iTunes, Apple Configurator or ios-deploy to add and retrieve files to the Documents folder of an application. If using iTunes to access the Documents folder of an application, please remember to synchronise the device for the changes to take effect.

SDK Configuration

The SDK configuration is an encoded string that is used to initialize the Approov SDK in your app.

How SDK Configuration Works

The SDK configuration is a base64 encoded JSON Web Token (JWT) providing information about the account holder. It contains the following information:

  • Name of the account
  • A public key that has been allocated to the account
  • Various configurable network access rules for the SDK
  • The set of API domains to protect along with any public key pinning information for them.

The JWT is signed using asymmetric Elliptic Curve Cryptography (ECC). The public key is in the configuration, but the private key is held securely in the Approov cloud service. This means that only the Approov cloud service is able to generate valid configurations. They cannot be manually modified as any tampering will be detected. The public key is transmitted by the SDK to the Approov cloud service, so any attempt to modify the public key and re-sign the configuration will also be detected.

By making the API domain pinning information available from the configuration, it is accessible upon startup of the app without the need for network access. Some app development frameworks require the pinning to be set at this point. More information about the pinning approach is provided in Public Key Pinning.

In order to support over-the-air dynamic updates to the configuration, the Approov cloud service can send an update if API domains or their pins (or some other parameter) is changed. Updates are also signed using ECC and the signature is checked against the public key provided in the initial base configuration. This prevents any tampering of the configuration in the communication channel.

Getting the Initial SDK Configuration

In order to initialize the SDK a configuration must be downloaded from the Approov cloud service using the approov tool.

$ approov sdk -getConfig initial.config
initial SDK configuration written to initial.config

In this case the configuration is written to the file initial.config. This file must be included inside the app to provide this information at runtime. This is described in SDK Initialization.

If the set of APIs and/or their pins are modified in the future, then the configuration becomes out of date. The app will continue to work because it will receive an updated configuration the next time it contacts the Approov service. However, it is better for the initial configuration to be as up to date as possible, so that it is available on the initial launch of an app even when it doesn’t have Internet access.

The approov tool issues app registration warnings whenever there is a pending download for a configuration change.

Handling Multiple Accounts

You may have access to multiple Approov accounts. Each account will have a different user roles in your Approov CLI. Furthermore, each account will have a different initial configuration for the SDK. This configuration will embed a different account name and also a different public key, since each account is allocated a different public/private keypair. This prevents a configuration for one Approov account being valid for another.

These different initial configurations will need to be carefully managed in your app development and build environments. Note that, the account name that is read from the configuration is always logged as part of the Approov SDK initialization, e.g. an example from Android logcat:

2019-05-23 16:41:43.139 32592-32592/com.criticalblue.demo I/Approov: test-account, com.criticalblue.demo, 2.0.4(1033), h4gubfCFzJu81j/U2BJsdg==

SDK Initialization

The steps required to initialize the Approov SDK are covered here. Configuration must be supplied to the SDK upon initialization. It is in the form of a string that is described in SDK Configuration. Saving and retrieving the dynamic configuration is not built into the SDK so that you can persist the configuration data in a way that best fits with the other data in your app.

This section provides a detailed reference for initializing the SDK at a low level. If you are able to use one of our Quickstart Frontend Integrations then this is done automatically as part of the integration.

Reading Initial SDK Configuration

This loads the initial configuration approov-initial.config from the assets of the app. In this example code we load it from a file. The name and folder location of this file may be adjusted depending upon the conventions of any particular app.


// read the initial configuration for the Approov SDK
String initialConfig = null;
try {
    InputStream stream = getAssets().open("approov-initial.config");
    BufferedReader reader = new BufferedReader(new InputStreamReader(stream, "UTF-8"));
    initialConfig = reader.readLine();
    reader.close();
} catch (IOException e) {
    // this should be fatal if the SDK cannot read an initial configuration
    Log.e(TAG, "Approov initial configuration read failed: " + e.getMessage());
}

// read the initial configuration
var initialConfig : String? = nil;
if let initialConfigURL = Bundle.main.url(forResource: "approov-initial", withExtension: "config") {
    do {
        initialConfig = try String(contentsOf: initialConfigURL)
    } catch {
        // it should be fatal if the SDK cannot read an initial configuration
        NSLog("Approov initial configuration read failed: \(error.localizedDescription)")
    }
} else {
    // it should be fatal if the SDK cannot read an initial configuration
    NSLog("Approov initial configuration not found")
}

Reading Dynamic SDK Configuration

The next step of the initialization is responsible for loading any dynamic configuration. In our example code we load it from a local file:


// read any dynamic configuration for the SDK from local storage
String dynamicConfig = null;
try {
    FileInputStream stream = getApplicationContext().openFileInput("approov-dynamic.config");
    BufferedReader reader = new BufferedReader(new InputStreamReader(stream, "UTF-8"));
    dynamicConfig = reader.readLine();
    reader.close();
} catch (IOException e) {
    // we can log this but it is not fatal as the app will receive a new update if the
    // stored one is corrupted in some way
    Log.i(TAG, "Approov dynamic configuration read failed: " + e.getMessage());
}

// read any dynamic configuration for the SDK from local storage
var dynamicConfig : String? = nil;
let URLs = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
let dynamicConfigURL = URLs[0].appendingPathComponent("approov-dynamic.config")
do {
    dynamicConfig = try String(contentsOf: dynamicConfigURL)
} catch {
    // log this but it is not fatal as the app will receive a new update if the
    // stored one is corrupted in some way
    NSLog("Approov dynamic configuration read failed: \(error.localizedDescription)")
}

This dynamic configuration approov-dynamic.config is held in the local file storage of the app. This configuration is optional, and when an app is launched for the first time it will not be present. The idea is that this allows a dynamically updated configuration for the app to be transmitted from the Approov cloud service to the app where it will be stored locally, and be available immediately the next time the app is started with no need to fetch it again over the network. This mechanism allows various aspects of the SDK behavior to be modified in the field, but crucially this is used to transmit updated public key pins to an app as is explained Public Key Pinning.

Starting the SDK

The next step is to actually start the SDK itself:


// initialize the Approov SDK
try {
    Approov.initialize(getApplicationContext(), initialConfig, dynamicConfig, null);
} catch (IllegalArgumentException e) {
    // this should be fatal if the SDK cannot be initialized as all subsequent attempts
    // to use the SDK will fail
    Log.e(TAG, "Approov initialization failed: " + e.getMessage());
}

// initialize the Approov SDK
do {
    try Approov.initialize(initialConfig!, updateConfig: dynamicConfig, comment: nil)
} catch {
    // it should be fatal if the SDK cannot be initialized as all subsequent attempts
    // to use the SDK will fail
    NSLog("Approov initialization failed: \(error.localizedDescription)")
}

On Android, Approov initialization requires the app Context. The initial and dynamic configurations are also provided. Remember the initialConfig must be non-null but the dynamicConfig may be null. The final string parameter is reserved for future use and should be set to null. If there is a problem with the initialization then an exception will be thrown and it will not be possible to execute further methods in the SDK.

Writing Dynamic SDK Configuration

There is one final step for the overall SDK initialization:


// if we didn't have a dynamic configuration (which happens after the first launch of the app) then
// we write it to local storage now
if (dynamicConfig == null)
    saveApproovConfigUpdate();


// if we didn't have a dynamic configuration (which happens after the first launch of the app) then
// we fetch one and write it to local storage now
if dynamicConfig == nil {
    saveApproovConfigUpdate()
}

This ensures that on the first execution of the app after installation an updated configuration is obtained from the Approov cloud service. If there is no update then the initial configuration is written as the updated configuration, indicating that it is the latest available.

This pattern implies that the first time your app is started, after installation, a network request will be made to determine if there is any updated dynamic configuration available (this will not count towards your device billing). This approach will immediately bring a fresh app install up to date with the latest configuration. This does mean, however, that there may be a small network delay at this time if there is poor network connectivity. No update attempt is made at all if there is no network connectivity.

This calls a user defined example method saveApproovConfigUpdate to save an updated configuration that is defined below. It should be defined as a separate method as it will need to be called whenever the SDK receives a new configuration from the Approov cloud service. This is provided as a code example outside of the Approov SDK so that you can modify it to use whatever file persistence makes the most sense for your particular app’s structure.


/**
 * Saves an update to the Approov configuration to local configuration of the app. This should
 * be called after every Approov token fetch where isConfigChanged() is set. It saves a new
 * configuration received from the Approov server to the local app storage so that it is
 * available on app startup on the next launch.
 */
public void saveApproovConfigUpdate() {
    String updateConfig = Approov.fetchConfig();
    if (updateConfig == null)
        Log.e(TAG, "Could not get dynamic Approov configuration");
    else {
        try {
            FileOutputStream outputStream = getApplicationContext().openFileOutput("approov-dynamic.config", Context.MODE_PRIVATE);
            PrintStream printStream = new PrintStream(outputStream);
            printStream.print(updateConfig);
            printStream.close();
        } catch (IOException e) {
            // we can log this but it is not fatal as the app will receive a new update if the
            // stored one is corrupted in some way
            Log.e(TAG, "Cannot write Approov dynamic configuration: " + e.getMessage());
            return;
        }
        Log.i(TAG, "Wrote dynamic Approov configuration");
    }
}

/**
 * Saves an update to the Approov configuration to local configuration of the app. This should
 * be called after every Approov token fetch where isConfigChanged is set. It saves a new
 * configuration received from the Approov server to the local app storage so that it is
 * available on app startup on the next launch.
 */
func saveApproovConfigUpdate() {
    let updateConfig = Approov.fetchConfig()
    if (updateConfig == nil) {
        NSLog("Could not get dynamic Approov configuration to save")
    } else {
        let URLs = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
        let updateConfigURL = URLs[0].appendingPathComponent("approov-dynamic.config")
        do {
            try updateConfig!.write(to: updateConfigURL, atomically: true, encoding: String.Encoding.utf8)
        } catch {
            NSLog("Approov dynamic configuration write failed: \(error.localizedDescription)")
        }
    }
}

This calls the newfetchConfig() method and obtains an updated configuration and writes it to local storage as approov-dynamic.config. This will then be read the next time the app is started without having to do a network fetch.

Reinitializing the SDK

Under normal circumstances it is only permissible to initialize the SDK once, and any attempt to initialize it a second time will result in an error.

There is one particular use case for Approov where a single app might be associated with several different Approov accounts, that might be selected as the app runs. Note though that the Approov SDK can only be associated with one account at a time.

Reinitialization is explicitly marked by providing reinit to the comment parameter of the initialization call.


// reinitialize the Approov SDK
try {
    Approov.initialize(getApplicationContext(), initialConfig, dynamicConfig, "reinit");
} catch (IllegalArgumentException e) {
    Log.e(TAG, "Approov reinitialization failed: " + e.getMessage());
}

// reinitialize the Approov SDK
do {
    try Approov.initialize(initialConfig!, updateConfig: dynamicConfig, comment: "reinit")
} catch {
    NSLog("Approov reinitialization failed: \(error.localizedDescription)")
}

Reinitialization is only supported in version 2.4.0 and later SDKs.

The SDK should not be reinitialized too frequently. The typical use case is that the reinitialization should only occur if the user of the app switches their account in some way, requiring access to a different set of backend APIs. Reinitialization should never be performed if there are in-flight asynchronous Approov token fetches.

If an app has access to multiple initial SDK configurations then care must be taken to also store separate dynamic SDK configuration updates for the different configurations.

Managing API Domains

This provides an overview of the management of API domains in the account. These correspond to the domains for which Approov tokens can be fetched.

Overview

Each Approov account has a set of API domains for which an app can fetch Approov tokens. These will typically correspond to the domains serving the APIs that are to be protected with Approov. An account may have a maximum of 25 different domains. API domains may be added and removed from the account as required.

In the app code, the fetchApproovToken or fetchApproovTokenAndWait calls are used to obtain a token. These calls have a required parameter specifying the target domain to be accessed, and a custom token for the specified domain is what’s provided by the SDK. Under the hood, each Approov attestation retrieves tokens for all registered domains and these tokens are cached securely until replacement tokens are retrieved by a new attestation.

There are a couple of motivations for specifying Approov token fetches with particular domains:

  • APIs that are protected with Approov tokens need to be pinned to prevent a Man-in-the-Middle (MitM) attack from stealing valid, albeit short lived, Approov tokens. Pinning needs to be based on the domain for the API since this determines the certificate that will be presented by the server.
  • It is possible that Approov tokens fetched for different domains are in a different format, or are signed using different secret keys. For instance, a particular domain may be setup to use encrypted (JWE) rather than symmetrically signed (JWS) tokens.

Domains are restricted to lower and upper case letters, digits, a dash and a period. This means that the API domain should not (and cannot) contain the full URI path to a particular resource.

There is no special handling of sub-domains so, for instance, mydomain.com and sub.mydomain.com are considered to be entirely distinct. Approov tokens should not be fetched for mydomain.com that are then sent to sub.mydomain.com. If required you can define a star.mydomain.com domain and fetch Approov tokens for sub domains from that. However, if using Approov dynamic pinning, you may have to define some special logic for the Public Key Pinning Implementation to convert the domain name into one that works for the pin.

Adding API Domains

A new API domain can be added to the account as follows:

$ approov api -add mydomain.com
WARNING: adding the API will have an immediate impact on your apps in production. If you wish to continue then please enter YES and return: YES
added new API domain mydomain.com with type:account, alg:HS256, pin:JG29gD8vWiEanTCVPjYLQ5yiYMKQqR05OH38yFf0kBU=
enabled continuous monitoring for https://mydomain.com:443 (remove using `approov monitoring -removeAPI`)

Confirmation is required whenever a new domain is added. This is because it has an immediate impact in production, with tokens being served for the new domain. As soon as a domain is added, tokens for the API domain can be obtained from fetchApproovToken or fetchApproovTokenAndWait calls, using the new domain as a parameter.

You should ensure that a pinning implementation is present in your app to actually pin the connection as explained in Public Key Pinning Implementation. New domains have a public key pin added derived from the public key of the leaf certificate presented on the domain. This pin can be used to protect the communication channel between the app and API domain to prevent any Man-in-the-Middle (MITM) attack between the app and the API backend. This is explained in detail in Public Key Pinning and is not covered further here. In some cases using a leaf pin might not be appropriate, so you should consult the team responsible for maintaining the certificates for the backend API. If the API domain that you wish to connect to is not on the standard port 443, you can use the -port option to select a different port from which to obtain the pinning information. Do not try and add the port to the API domain itself as this is not valid.

By default, newly added domains are included for continuous API monitoring. This means that you will receive an email notification if the API domain becomes inaccessible or the certificates it presents no longer match the pins in the account. Note though that you must setup the email recipients to receive these notifications.

By default, Approov tokens for a particular API will be issued as signed JWS tokens using the account secret key. Approov also provides an option to issue encrypted JWE tokens for a domain. This is enabled by using the -jweoption when adding the new API domain. The Approov token format is covered in more detail here.

Once you have added an API domain it is not possible to edit its attributes. If you wish to do this, simply remove the API domain first and then add it again with the revised configuration.

As explained, adding a domain in this way will set a pin based on the leaf certificate presented from the domain. This may then be used by your app to pin the connections that it makes to that domain. Pinning connections in this way significantly increases security, however, there is a danger that you app will stop communicating with the API if the certificates on the domain change and the public key of the certificate is not preserved. To avoid this, you should try to manage your backend APIs so that the same public key is used when certificates are rotated. However, if this is not possible, Approov does give you the flexibility of dynamically updating pins if required and, by default, you will receive an email from the API monitoring that will warn you of a pin mismatch.

Keyset Key API Addition

If you have added one or more keyset keys then you can add an API domain that uses one of those keys as follows:

$ approov api -add mydomain.com -keySetKID mykey
WARNING: adding the API will have an immediate impact on your apps in production. If you wish to continue then please enter YES and return: YES
added new API domain twitter.com with type:keyset, alg:RS256, kid:mykey, pin:kJ8+U7wNPfc5vxwnQYvlffbaZA6wwCvd/eC8YMpB+sU=
enabled continuous monitoring for https://mydomain.com:443 (remove using `approov monitoring -removeAPI`)

This adds the domain using the keyset key mykey. This means that all Approov tokens issued for the domain will be signed or encrypted with the specified key. The key identifier will appear in the kid claim in the header. The particular algorithm to be used is also defined by the key, allowing a wide range of choices including asymmetric options which can ensure that the Approov cloud service is the only entity capable of generating valid tokens signed with the private key, which the tokens can be verified by your backend using the public key.

Adding Pin Only API Domains

An option is provided to add an API domain which only uses the Approov pinning facilities and does not need Approov tokens to be sent. Do this as follows:

$ approov api -add myotherdomain.com -pinOnly
WARNING: adding the API will have an immediate impact on your apps in production. If you wish to continue then please enter YES and return: YES
added new API domain myotherdomain.com with type:pinOnly, pin:kJ8+U7wNPfc5vxwnQYvlffbaZA6wwCvd/eC8YMpB+sU=
enabled continuous monitoring for https://myotherdomain.com:443 (remove using `approov monitoring -removeAPI`)

The purpose of this is to allow access to the pinning features of Approov without the need to send Approov tokens. This option should therefore only be used on endpoints where it is not necessary or possible to add Approov token checking on the backend.

Any attempt to get a token for the domain results in an UNPROTECTED_URL / unprotectedURL status from the Approov token fetch call. The Quickstart Frontend Integrations continue with the request in this case without adding an Approov token.

Listing API Domains

A list of all the domains that are configured for the account can be obtained with:

$ approov api -list
2 API domains:
 mydomain.com       type:account, alg:HS256
 shapes.approov.io  type:restricted, alg:HS256

This provides information about all of the domains that have been added and their attributes. The type attribute may be:

  • account: This is the default, indicating that the account secret key is used.
  • restricted: Indicates that the keys and pins for the domain are centrally managed by Approov.
  • keyset: Indicates that the key used for the domain is one from the keyset.
  • pinOnly: Indicates that the domain has been added to enable pin management and that no tokens will be issued for it by the Approov service.

The alg attribute shows the type of algorithm used for signing or encrypting the Approov tokens. By default, for account type tokens, the HS256 signing algorithm is used. However, if the -jwe option was used then the A256GCMKW JWE encryption algorithm is used instead. For a keyset type a wider range of algorithms are avaialble.

The kid attribute, and the associated value, is shown if the domain has been configured to use a JWT KeySet entry. The specified key ID will be included in the header of all subsequent tokens issued for the domain.

The monitorPort property is included if contiuous monitoring has been enabled for the domain (the default). This displays the port being used to probe the domain, normally 443. (See API Monitoring)

Approov tokens are only served, for an account, for those APIs listed by this command. Any attempt to get a token for another domain results in an UNKNOWN_URL / unknownURL error from the Approov token fetch call.

Removing API Domains

An API domain that has been previously added can be removed with the following command:

$ approov api -remove mydomain.com
WARNING: removing the API will have an immediate impact on your apps in production. If you wish to continue then please enter YES and return: YES
removed API domain mydomain.com

Note that removal of an API domain requires an administration role and further confirmation is required before the domain is removed. Note that this means that Approov tokens will no longer be served for that domain. You obviously must be careful not to remove a domain that is being used by production apps as this will lead to a production outage.

Adding Demonstration Shapes API

A special shapes domain (managed by the Approov team) can be added to your account:

$ approov api -add shapes.approov.io
WARNING: adding the API will have an immediate impact on your apps in production. If you wish to continue then please enter YES and return: YES
added new API domain shapes.approov.io with type:restricted, alg:HS256

This domain serves a very simple API that provides random shapes and it is used by the Approov demo app. Any account can add this domain to generate Approov tokens for the API. The type is shown as restricted meaning that it has the special property that the associated Approov tokens with a secret key expected by that API rather than the standard one for the account. Moreover, you are not able to modify the pins associated with that domain.

Fetching Approov Tokens

This section describes the methods that should be used to obtain an Approov token from the SDK. This is the token that is required to pass to a subsequent backend API call.

This section provides a detailed reference for fetching Approov tokens at a low level. If you able to use one of our Quickstart Frontend Integrations then this is done for you as part of the integration, typically as an interceptor. The quickstart integrations also implement pinning.

You should never cache an Approov token in your app code. Always make a call to fetch a token immediately prior to making an API request that needs it. The Approov SDK automatically caches the Approov token and only performs a network request if a new one is required. Moreover, the SDK performs additional fast checks on app integrity every time an Approov token is fetched.

Once your app is able to fetch Approov tokens, we strongly recommend that you also implement Pinning. As well as protecting your users’ data, this will also protect Approov tokens from being stolen with a Man-in-the-Middle attack.

Token Fetch Errors

Whenever an Approov token fetch is performed there are a set of different success or error results that may occur. These provide more information about the reason for any token fetch failure, either for debug analysis or to determine how the app should react.

Until you have Added the API Domain that you are fetching an Approov token for, as provided in the URL parameter to the fetch, you will receive an UNKNOWN_URL / unknownURL error.

Even if you successfully fetch an Approov token it may not be valid. When first using Approov it is a common mistake to forget to Register Your App or remember that, unless you whitelist your device, the token will also be invalid due to Approov’s debug detection if you are launched your app through the development environment.

These potential errors are enumerated in the table below along with the recommended action and a description of the associated meaning. Note that all iOS errors are prefixed by ApproovTokenFetchStatus..

Error (Android / iOS) Rcmd Description
SUCCESS / success Continue Indicates that an Approov token was successfully retrieved.
NO_APPROOV_SERVICE / noApproovService Continue Indicates that no token could be obtained in the unlikely event that Approov cloud services are completely down (including the failover service) or, more likely, that the account has been cancelled. The error might also occur if an app is using an old version of the Approov SDK that has no active registrations and has been deprecated and removed from the Approov cloud systems In this case the error should be propagated to the actual API call to allow Approov token checking to be disabled on the API backend.
NO_NETWORK / noNetwork Retry Indicates no token was received because there is no network connectivity. The SDK checks for network connectivity before making a token fetch attempt. This allows a rapid return from the token fetch if there is no connectivity. If this error is received then there is no point in proceeding with any following API call which will also require network access. A timed, or user initiated, retry is required.
POOR_NETWORK / poorNetwork Retry Indicates that no token could be obtained due to poor network connectivity. If this error is received then there is no point in proceeding with any following API call which will also require network access. A timed, or user initiated, retry is required.
MITM_DETECTED / mitmDetected Retry Indicates that there is a Man-In-The-Middle (MITM) in the communication with the Approov cloud service. This may be malicious or may simply indicate that the end user is using a network with a firewall that intercepts all traffic for inspection. If this error is received then there is no point in proceeding with any following API call which will also require network access. A timed, or user initiated, retry is required.
BAD_URL / badURL Error Indicates that the provided URL is not in the correct format. The URL should just be provided as a domain, although a full URL path may be specified from which the domain is extracted. This error can occur if such a URL is provided with a http:// rather than the https:// scheme.
UNKNOWN_URL / unknownURL Error Indicates that the provided URL is not an API domain configured for use.
UNPROTECTED_URL / unprotectedURL Continue Indicates that the provided URL is valid but is not one that needs to be provided with an Approov token. The request should continue without adding an Approov token.
NO_NETWORK_PERMISSION / NA Error For Android, indicates that the app does not have ACCESS_NETWORK_STATE or INTERNET permission.
MISSING_LIB_DEPENDENCY / NA Error For Android, indicates that the Approov SDK dependency on the OkHttp library has not been satisfied.
INTERNAL_ERROR / NA Error For Android, indicates there has been an internal error within the SDK. Please contact Approov support if this ever happens.
NA / notInitialized Error For iOS, indicates that an attempt is being made to use an SDK method before it has been initialized. Note that the Android SDK generates an exception in this case.

The Rcmd column shows our recommendation for how the app logic should proceed if it receives the given error state. There are three possible options:

  • Continue: Indicates that the app should go ahead and make the API call as expected. Together with the success case, we also include the case where no Approov service is detected. In this case, the API call will be made with an empty token, so should be rejected by the Approov check in the API backend. Our recommendation, to continue, is provided to guard against some catastrophic failure or cancellation of your Approov service. This will ensure that your app will continue to operate as normal without the Approov service if you choose to disable the backend API check for the Approov token. If you integrate Approov in the recommended way then this circumstance should be the only legitimate reason to receive empty tokens on your API backend. Another, illegitimate, reason would be because an attacker is trying to spoof API requests but without a valid Approov token. If you unexpectedly receive large numbers of empty tokens on the backend and you suspect that this is caused by an Approov service failure then please contact our support immediately.
  • Retry: Indicates that the app should not attempt the API call. This is because it has not been possible to fetch an Approov token due to some network conditions. The Approov SDK already makes various retries, so there is probably no point in performing a further automated retry. Instead, the retry should require a further user initiated event. The typical case will be when the device has no (or very poor) network connectivity, so some user initiated event is required to retry when connectivity has been restored. Note that a special message might be appropriate if MITM is detected on the Approov channel, as the network being used might be inappropriate as it intercepts TLS. The user will need to connect to a different network to use the app.
  • Error: This indicates an error condition that really should not occur in a production app. We recommend that this condition is logged with any crash reporting SDK that you may be using. The next step will depend on your general strategy for error handling. You could go ahead and make the API call, but use the loggable token as the Approov token. This will of course be rejected by the backend, but will provide loggable information there.

Note that if an API domain, in active usage, is accidentally removed from your Approov account then this will lead to an error indication as the token fetch attempt will receive an Unknown URL error.

Note in cases where you are using an interceptor pattern to add your Approov token you should treat the Unprotected URL case correctly. You get this on domains that have been added with the -pinOnly option. Thus you should continue with the request without adding an Approov token.

Synchronous Token Fetching

This describes how to fetch an Approov token with the synchronous form of the call. This method does not return until a token has been fetched. If a cached token may be used, then the call will return promptly. If a new token is required, then the call will include the time to complete the network requests with the Approov cloud service and so there may be some delay before returning. The exact delay will depend on many factors, especially network connectivity quality. This should not be called from a UI thread since the OS might force stop your application.

You must never make this call directly from the main or UI thread of your application. This is a potentially long running blocking call, and there may be unpredictable delays and effects on your app if it blocks UI processing.

The code to make the call is very simple, as follows:


Approov.TokenFetchResult approovResult = Approov.fetchApproovTokenAndWait("api.myservice.io");
if (approovResult.isConfigChanged())
    saveApproovConfigUpdate();

let approovResult = Approov.fetchTokenAndWait("api.myservice.io")
if approovResult.isConfigChanged {
    saveApproovConfigUpdate()
}

The method takes a parameter of the particular API domain for which a token is being fetched. This must be one that has been configured to provide Approov tokens or else an error will result.

Whenever a token fetch is performed, the recommended pattern is to check whether any new configuration has been transmitted to the app and, if so, use the saveApproovConfigUpdate method to save it locally. This means that this configuration will be available immediately on the next app startup, even if there is no network connectivity at the time. The availability of the new configuration is checked using the isConfigChanged() getter in the returned fetch result. Note that this flag remains set until a fetchConfig() method, as used in saveApproovConfigUpdate, is called. The method saveApproovConfigUpdate is defined here. If it is not convenient or appropriate to update the configuration at that point (perhaps if the token fetching is in an interceptor) then a flag can be set to cause the update to occur at some later, more appropriate point in the code flow.

Next, check the status returned from the fetch, and react appropriately:


String token = approovResult.getToken();
if ((approovResult.getStatus() == Approov.TokenFetchStatus.SUCCESS) ||
    (approovResult.getStatus() == Approov.TokenFetchStatus.NO_APPROOV_SERVICE)) {
    <pass handling>
} else if ((approovResult.getStatus() == Approov.TokenFetchStatus.NO_NETWORK) ||
           (approovResult.getStatus() == Approov.TokenFetchStatus.POOR_NETWORK) ||
           (approovResult.getStatus() == Approov.TokenFetchStatus.MITM_DETECTED)) (
    <retry handling>
} else {
    <error handling>
}

let token = approovResult.token
if (approovResult.status == ApproovTokenFetchStatus.success) ||
   (approovResult.status == ApproovTokenFetchStatus.noApproovService) {
    <pass handling>
} else if (approovResult.status == ApproovTokenFetchStatus.noNetwork) ||
          (approovResult.status == ApproovTokenFetchStatus.poorNetwork) ||
          (approovResult.status == ApproovTokenFetchStatus.mitmDetected) {
    <retry handling>
} else {
    <error handling>
}

These represent the three classes of response, as discussed in the previous section. The exact implementation will depend on the structure of your app:

  • Pass Handling: Should go ahead and make the API call for the domain for which the Approov token was fetched.
  • Retry Handling: The API call should not be made, and instead another attempt should be made to fetch an Approov token after a user initiated retry.
  • Error Handling: This is for error conditions that should not normally occur. Logging and/or crash analytics should be used. Although the app may continue, it should not proceed with the API call as the token string will be empty.

Note that the token fetching process itself may make various retries of the communication with the Approov server. Within the SDK, the absolute worst case timeout before the method returns is typically configured to be 30 seconds.

Asynchronous Token Fetching

An alternative Approov token fetch calling mechanism is provided. This uses an asynchronous approach whereby a callback method is provided. This is called either when an Approov token is available or there is an error. This method allows token fetches to be initiated from threads that cannot be blocked, such as UI threads.


class ApproovCallbackHandler implements Approov.TokenFetchCallback {
    @Override
    public void approovCallback(Approov.TokenFetchResult pResult) {
        if (pResult.isConfigChanged())
            saveApproovConfigUpdate();
        switch (pResult.getStatus()) {
            case Approov.TokenFetchStatus.SUCCESS:
            case Approov.TokenFetchStatus.NO_APPROOV_SERVICE:
                // Go ahead and make the API call with the 'pResult.getToken()'
            case Approov.TokenFetchStatus.NO_NETWORK:
            case Approov.TokenFetchStatus.POOR_NETWORK:
            case Approov.TokenFetchStatus.MITM_DETECTED:
                // We should retry doing a fetch after a user driven event
            default:
                // There has been some error event that should be reported
        }
    }
}

// omitted code for brevity

ApproovCallbackHandler approovCallback = new ApproovCallbackHandler();
Approov.fetchApproovToken(approovCallback, "api.myservice.io");

Approov.fetchToken({ (approovResult: ApproovTokenFetchResult) in
    if approovResult.isConfigChanged {
        saveApproovConfigUpdate()
    }
    switch approovResult.status {
    case ApproovTokenFetchStatus.success,
         ApproovTokenFetchStatus.noApproovService:
         // Go ahead and make the API call with the 'approovResult.token'
         <pass handling>
    case ApproovTokenFetchStatus.noNetwork,
         ApproovTokenFetchStatus.poorNetwork,
         ApproovTokenFetchStatus.mitmDetected:
          // We should retry doing a fetch after a user driven event
          <retry handling>
    default:
        // There has been some error event that should be reported
        <error handling>
    }
}, "api.myservice.io")

For Android, a class must be defined that implements the Approov.TokenFetchCallback interface. For iOS, a closure may be defined within the call. All other handling should follow the same logic as described in the preceding sections.

Token Fetch Latency

The integrity check operation provided by Approov requires the SDK to perform a CPU computation and possibly one or more network requests. A Cached Fetch, as its name implies, returns an already available token and does not require much additional computation or any network connection. The table below provides an average of values obtained by measuring the performance of an Approov token fetch operation on a range of devices for both Android and iOS with good network conditions. Moreover, the devices were located in Europe or the US West Coast, geographically close to our AWS points of presence for the Approov cloud. The type of token fetch mechanism (synchronous or asynchronous) does not impact the latency.

Platform Network Fetch Cached Fetch
Android 950 ms 50 ms
iOS 750 ms 35 ms

The iOS Approov SDK can optionally perform additional device checks using the Apple DeviceCheck capability. If this option is used then the Approov SDK must make a call to generate a token to identify the device. This needs to be done on the first Approov token fetch after installing the app. Performing this operation requires additional network connection(s) and CPU processing time, over which the Approov SDK has no control. This can substantially delay the fetch operation on the iOS platform by adding up to 2500 ms of additional latency. If you are using this option, consider asynchronously prefetching an Approov token as early as possible to help hide this latency.

The Android Approov SDK can optionally perform SafetyNet attestation. If this option is used then the Approov SDK must make an attestation call. This needs to be done on the first Approov token fetch after installing the app. Performing this operation requires additional network connection(s) and CPU processing time, over which the Approov SDK has no control. This can substantially delay the fetch operation on the iOS platform by adding up to 3500 ms of additional latency. If you are using this option, consider asynchronously prefetching an Approov token as early as possible to help hide this latency.

If you are using Android and your app is being released as an App Bundle, this will cause an increase to the latency of the first Approov token fetch after launching the app by an amount determined by the size of the APK and the performance of the device on which the app is running. This can add up to 1300ms for a 30MB APK on an entry-level device, but is 500ms or less for mid and high performance devices.

Managing Registrations

App registration management determines the set of apps that the Approov service will consider valid for the account.

Android App Signing Certificates

This section is only relevant if you are using Android and are registering an app that is being released as an App Bundle.

Google has rolled out a new application packaging format for Android applications. The Android Application Bundle (AAB) includes platform, screen density, and language variants needed for application installation on any device. After a bundle has been uploaded to the Play Store, each device installation will include only the specific platform, density, and language features needed by that device. The installation is delivered using Android’s split-APKs feature, and post-installation dynamic feature modules can be provided on demand using supplemental APKs.

In order to use App Bundles with Approov you need to inform Approov about the app signing certificates that you use. These are remembered in your Approov account so it is only if you add a new certificate or revoke an old one that you will need to complete this step again. An app signing certificate proves that a particular installed app package has been issued by Google via your account. The public key of the certificate allows an encrypted digest of your full app content to be verified. Recreating a valid signature for a modified app requires access to the private key associated with the certificate, which is inaccessible except to Google.

The app signing certificate is available in your Google Play console. Log in and navigate to the release management section for your app. You will see a screen similar to the following:

Google Play App Signing

The section App signing certificate shows the signing certificate that is currently active, and its hash in various forms. Download the .der certificate file by clicking on the DOWNLOAD CERTIFICATE button. Save it as app-signing-cert.der, or some other convenient name. Note that there is no risk of key compromise by doing this since it is a public certificate and the private key is not included.

You can add the signing certificate to Approov with the following command:

$ approov appsigncert -add app-signing-cert.der
successfully added C0:F3:15:9B:A5:6C:A8:E1 | Subject: CN=ANOther,O=CriticalBlue,L=Edinburgh,C=UK | Expiry: 21 May 2041

This adds the certificate to those that are known by Approov. The first 8 bytes of the SHA256 hash of the certificate are shown in hex. This matches the value SHA-256 certificate fingerprint shown in the Google Play Console. Other certificate metadata and the expiry date are also output.

Approov will now be able to recognize apps that have been signed with this certificate. The Approov SDK does an analysis of the app signature as part of its analysis to ensure that only your app is able to obtain a valid Approov token. Note that in addition to providing the correct signing certificate, you also need to register the specific app version.

You may add up to 10 different app signing certificates to the Approov account. This allows apps with different signing certificates. These may be from different Google Play accounts, allowing them to be supported in a single Approov account. Moreover, if you upgrade or change your app signing certificate in the Google Play console you should keep the old one in the Approov account as there will be installed versions of your app still using it.

It is not necessary to go through the Play Store console to test using an app bundle with Approov. You can use Android Studio ‘Build → Build Bundle(s)/APK(s) → Build Bundle(s)’ to build an app bundle which will be automatically signed with the debug key from your debug keystore (debug.keystore) or you can use ‘Build → Generate Signed Bundle / APK…’ to build an app bundle and sign it with a key from another key store.

Locate the signed app bundle you have just built and follow the bundletool instructions on Generate a set of APKs from your app bundle and Deploy APKs to a connected device to deploy the app bundle to a test device. The installation section describes how bundletool can be obtained.

For Approov to recognize app bundles built and deployed in this way, you need to add the app signing certificate to Approov, for the key that you used to sign the app bundle. The app signing certificate can be extracted from the key store using the Java keytool, which comes as part of your Java installation (Java can be installed from here). Issue a command such as this, substituting the key alias and filenames to match the key store you are using.

$ keytool -exportcert -keystore debug.keystore -alias androiddebugkey -file androiddebugkey-app-signing-cert.der
Enter keystore password:  
Certificate stored in file <androiddebugkey-app-signing-cert.der>

Then, using the approov tool, add the exported app signing certificate as described above. Keep in mind that the number of app signing certificates in Approov is limited to 10. Sharing of debug or development keystores among a development group is advised.

You can list the current app signing certificates as follows:

$ approov appsigncert -list
1 app signing certificate:
 C0:F3:15:9B:A5:6C:A8:E1 | Subject: CN=ANOther,O=CriticalBlue,L=Edinburgh,C=UK | Expiry: 21 May 2041

An app signing certificate can be removed with:

$ approov appsigncert -remove C0:F3:15:9B:A5:6C:A8:E1 
WARNING: removing an app signing certificate will have an immediate impact on your apps in production. If you wish to continue then please enter YES and return: YES
successfully removed app signing certificate with fingerprint C0:F3:15:9B:A5:6C:A8:E1

Use the shortened fingerprint hash to select the appropriate certificate. Note that removal requires an admin role and user confirmation.

Adding or removing an app signing certificate does not have an immediate impact on the validity of registration. The impact is only for apps which are started 30 seconds or more after the change. Contrast this with the app registrations themselves which are actioned within 30 seconds for the next time an app fetches an Approov token (typically a maximum of 5 minutes), with no need to restart the app.

App signing certificates are also employed if you utilize the SafetyNet Integration option to check the certificate hash provided in the SafetyNet token.

Approov supports the signature algorithms in the list of signature algorithm IDs on the Android Open Source Project’s web-site.

If your app bundle includes other native libraries that include architectures that are no longer supported, then you may wish to remove them from your build and only include the relevant architectures using ABI Filters. For instance, you can use abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64' to restrict to Approov supported architectures only. We have had reports that without this an incorrect package of native libraries can be delivered to certain devices and cause the Approov libapproov.so to be missing and thus the Approov SDK cannot be initialized.

Registering an App

The Approov service is designed to only send a valid Approov token to apps that have been registered. Registration indicates that Approov has captured the fingerprint of a good instance of your app and should, subject to various other checks and conditions, deliver valid Approov tokens to any identical app instance. Any other app cannot receive valid Approov tokens and will therefore be unable to access the backend API services that you have protected with Approov.

When you release a new version of your app to the app store, you will need to register the final version that will be published. Multiple different versions of the app registration may be live simultaneously to support end users who are running different versions of the app. In general it may take some time for users’ apps to be updated to the latest version. You may also wish to register various versions of the app during the development and test process.

In order to register an app you need the app package that is to be run. This is either an .apk or .aab file (Android) or an .ipa file (iOS). An app being registered must have the Approov SDK integrated within it or else the registration will fail.


$ approov registration -add my_app.apk
registering app
 Ac15BRFWqxn79dGsjOdVJXVqBQQ64ZWTAuKdrzRC9hc=my.app.com-2.0[3]-1042  SDK:Android(2.5.0)
registration successful

$ approov registration -add my_app.ipa
registering app
 DRJNqt37tsdHwb9FKFT80dPqXlOHqZnZy68zAiVSsvM=my.app.com-2.0[3]-1041  SDK:iOS(2.5.0)
registration successful

The message indicates that an overall signature of the app, its name and its version have been extracted and are available for viewing in the list of all registrations for the account. The overall signature consists of a signature hash of aspects of the application, the application package name, application version information, and the ID of the Approov SDK that is integrated within it. Finally, information about the type and version number of the Approov SDK used is also provided.

Once an app is registered, it should be possible to get valid Approov tokens for it, assuming there are no other issues with the device or its runtime environment (for instance, a debugger being active) that prevent it from receiving a valid token.

By default, an app registration is permanent and will remain in the Approov cloud database until it is explicitly removed. Permanent app registrations should be used to identify apps that are being published to production.

If you are registering an iOS app then remember you will need to remove simulator architectures before publishing to the App Store. If you are registering an Android app that you intend to publish to the Play Store, you must ensure that it is signed with a V2 signature (or later) or else the registration will not match the Play Store version and it will not receive valid Approov tokens.

If you are registering an Android App Bundle (.aab file) then the approov tool needs access to bundletool. The installation section describes how to get this tool. Use either the APPROOV_BUNDLETOOL environment variable or the -bundletool parameter with the registration command to specify the location of the bundletool jar file. Note also that you must use an SDK that is version 2.3.0 or later. Note also registering an app as an App Bundle will cause an increase to the latency of the first Approov token fetch after launching the app. For details please see Token Fetch Latency.

It is only possible to have a maximum of 250 registrations at any one time.

Registration Upgrade Messages

When an app is registered, you may receive two different types of upgrade advisory messages. These are generated to assist you with keeping Approov usage up to date. The possible messages are as follows:

  • SDK Library Upgrade: If you receive a message such as note: newer version 2.6.0 of the Approov Android SDK is available or similar, then this indicates that the Approov SDK integrated in the app is not the latest one available. You should consider upgrading before making a new release of the app. The latest SDK library package can be obtained via the approov tool and then integrated in the app to replace the old version. Release notes are available here.
  • SDK Configuration Upgrade: You may receive a message such as WARNING: SDK initial configuration must be out of date since a new one is available. This means that there have been some changes to the SDK initial configuration that are probably related to changes to the API domains served and their pins. It might also be related to some change that the Approov service itself has made. If you see this, then you should upgrade your initial SDK configuration inside the app to ensure it has the most up to date version when released. The app can of course get a dynamic update over-the-air, but it is always best to ship new apps with the latest version.

Temporary Registrations

By default an app registration is permanent. This also means that an admin role is required to remove it. Removal needs to be restricted since an accidental removal will stop apps in production from receiving valid tokens, which may effectively bring an app service down. Note that in such a circumstance the Approov failover system will not be enabled, since this is not an Approov cloud system failure but explicit user action.

A temporary registration is performed just like a permanent registration, but with the addition of the -expireAfter option.

$ approov registration -add my_app.ipa -expireAfter 3d
registering app MyCoolApp
 P6nTmI3fhftxUr740ZnUMGKuAyTYjxP5dxKzJGd9yOk=my.app.com-2.0[3]-2974  SDK:iOS(2.5.0)
registration successful, expires 2019-06-01 16:27:01

This creates a registration that is active for 3 days. The expiry time is given in local time in the output. Note though, if the registration already exists and is permanent or has a longer lived temporary expiration time, then that later time is retained.

The -expireAfter parameter takes a duration which may be specified in y (years), d (days), h (hours), m (minutes) or s (seconds). Multiple time units may be used as long as they are specified in this order, e.g. 3d12h to register for three and a half days.

Unversioned Registrations

By default an app registration is for a specific version of the app. This means that a new app registration is required each time a new app is released. This gives the flexibility of fine grain control of your registrations, allowing you to remove individual registrations associated with specific versions (perhaps if you no longer wish to issue valid Approov tokens to an oldler version of your app).

However, it is possible to create an app registration that is not specific to a version. This will match any app issued with the same signing authority and with the same package name. If you use this style, then only one registration is required and any updated app release will also match. Remember that you lose the flexibiliuty of revoking individual versions in the future.

An unversioned registration is performed with the addition of the -unversioned option. Note that this is not supported for Android .apk packages, only for .aab.

$ approov registration -add my_app.ipa -unversioned
registering app MyCoolApp
 guwtV9sOk0AaEqE08mWKu32X6x8HuyBqMalrN2UcD64=my.app.com-*-5647  SDK:iOS(2.6.0)
registration successful

This creates an unversioned registration, denoted by the * in place of the version number.

Unversioned registration is only supported in version 2.6.0 and later SDKs.

Listing Registrations

All of the registrations that are active for the account can be listed as follows:

$ approov registration -list
3 app registrations:
 Ac15BRFWqxn79dGsjOdVJXVqBQQ64ZWTAuKdrzRC9hc=com.criticalblue.demo-2.0[3]-2974                   SDK:Android(2.5.0)  registered:2019-05-15 18:03:17
 P6nTmI3fhftxUr740ZnUMGKuAyTYjxP5dxKzJGd9yOk=approov.io.client.swift.shapes-client-1.0[1]-4803   SDK:iOS(2.5.0)  registered:2019-05-15 18:03:31
 Ac15BRFWqxn79dGsjOdVJXVqBQQ64ZWTAuKdrzRC9hc=com.criticalblue.demo-2.0[3]-2974                   SDK:Android(2.5.0)  registered:2019-05-29 14:49:36 expiry:2019-06-01 14:49:36

Each registration entry provides its overall signature as a single text block at the start of each line. This is the signature that must be copied in order to remove a registration (see next section). It contains a signature hash of aspects of the application, the application package name, application version information, and the ID of the Approov SDK that is integrated within it.

More information is also provided about the type and version number of the Approov SDK used. The registration time of the app is also provided (in local time). This is updated if a new registration of an app is made that happens to have the same signature. Finally, the expiry time of the registration is shown if it was registered with -expireAfter. Once a registration expires it is automatically removed from the list.

Note that if you are looking for a particular registration you are able to find it by simply piping the output through grep, for instance on Linux/MacOS:

$ approov registration -list | grep iOS
 P6nTmI3fhftxUr740ZnUMGKuAyTYjxP5dxKzJGd9yOk=approov.io.client.swift.shapes-client-1.0[1]-4803  SDK:iOS(2.5.0)  registered:2019-05-15 18:03:31

Using this method it is possible to find registrations for specific platforms, SDK versions, app names and versions.

Removing Registrations

Any individual registration can be removed using its overall signature provided from the registration -listoption. For instance, to delete a temporary app registration:

$ approov registration -remove Ac15BRFWqxn79dGsjOdVJXVqBQQ64ZWTAuKdrzRC9hc=com.criticalblue.demo-2.0[3]-2974
app registration Ac15BRFWqxn79dGsjOdVJXVqBQQ64ZWTAuKdrzRC9hc=com.criticalblue.demo-2.0[3]-2974 has been removed

You will be asked for confirmation if the app has a permanent registration, but not for a temporary registration. When a registration is removed no further valid Approov tokens will be issued for the app, with a delay of up to 30 seconds for this deletion operation to propagate through the Approov servers. Note that running apps may already hold a cached Approov token so it may take up to 5 minutes more before all valid token usage by those apps stops.

Permanent app registrations are removed in the same way but users are also asked to provide confirmation before the deletion occurs. An admin role can be used to remove any registration. Registrations that were added with an admin role can only be removed with an admin role (it doesn’t need to be the same user). A user’s dev role can be used to remove registrations that they added using a dev role. In other words, a developer can remove their own permanent registrations but not those added by other users.

$ approov registration -remove P6nTmI3fhftxUr740ZnUMGKuAyTYjxP5dxKzJGd9yOk=approov.io.client.swift.shapes-client-1.0[1]-4803
WARNING: removing app registration will have an immediate impact on your apps in production. If you wish to continue then please enter YES and return: YES
app registration P6nTmI3fhftxUr740ZnUMGKuAyTYjxP5dxKzJGd9yOk=approov.io.client.swift.shapes-client-1.0[1]-4803 has been removed

If you are using the zsh shell you will need to enclose the -remove parameter with single quotes. This is because zsh interprets square brackets as a globbing specifier.

Removing Multiple Registrations

A facility is provided to remove multiple registrations using a single command. This is useful for maintaining the hygiene of your app registrations. You should actively remove registrations that are no longer in use, either because they are registrations for old testing apps (that have been accidentally permanently registered), or for previously released production apps that no end users are still using. The command is invoked as follows:

$ approov registration -removeMatching com.criticalblue.demo,30d
2 matched registrations:
 Ac15BRFWqxn79dGsjOdVJXVqBQQ64ZWTAuKdrzRC9hc=com.criticalblue.demo-2.0[3]-2974  registered:2019-05-05 16:01:46
 A4rcdXpfEOg0wse4snbAURnjRZidPvY63EULzUrZeFE=com.criticalblue.demo-3.0[4]-2974  registered:2019-05-15 18:02:08
WARNING: removing app registrations will have an immediate impact on your apps in production. If you wish to continue then please enter YES and return: YES
removing Ac15BRFWqxn79dGsjOdVJXVqBQQ64ZWTAuKdrzRC9hc=com.criticalblue.demo-2.0[3]-2974
removing A4rcdXpfEOg0wse4snbAURnjRZidPvY63EULzUrZeFE=com.criticalblue.demo-3.0[4]-2974

This needs an administration role as this is a risky operation that could cause current production app registrations to be removed if care is not taken. The parameters provide the exact package name of apps to be matched and the minimum age of last registration of the app. In this case it is 30 days i.e. in this case, the command will only remove apps last registered more than 30 days ago. A list of matching registrations is provided. You should review this carefully before allowing the operation to complete.

Annotating a Registration

A facility is provided to add an arbitrary string instead of the version name for a particular registration. This allows a particular registration to be annotated to show that it is for some specific purpose (perhaps a special testing version, for instance) and this allows it to be easily located in the list of all app registrations. We advise you not to use this facility on apps which are to be retained for production purposes, so that the real version number of app registration is available.

The annotation is added as follows:

$ approov registration -add my_app.apk -versionName "special"
registering app
 Ac15BRFWqxn79dGsjOdVJXVqBQQ64ZWTAuKdrzRC9hc=my.app.com-special-1041  SDK:Android(2.0.4)
registration successful

This particular registration can then be easily found again:

$ approov registration -list | grep special
Ac15BRFWqxn79dGsjOdVJXVqBQQ64ZWTAuKdrzRC9hc=com.criticalblue.demo-special-1041  SDK:Android(2.0.4)  registered:2019-05-29 17:07:22

Special Library Registration

By default, the SDK library ID for an app is determined by the approov tool that analyses the app to be registered. In some cases though an Approov SDK may itself be embedded inside another SDK within the app. In this case the tool cannot automatically locate the SDK and, in any case, it is possible for there to be more than one Approov SDK in the app.

In such a case you must use the specific ID of the Approov SDK that you want to register with. This can be specified with an additional command line option as follows:

$ approov registration -add my_app.apk -libraryID 1056
registering app
 Ac15BRFWqxn79dGsjOdVJXVqBQQ64ZWTAuKdrzRC9hc=my.app.com-2.0[3]-1056  SDK:Android(2.0.2)
registration successful

Registration Cloning

A registration cloning option is provided to support a use case employed by certain Approov customers. In this use case the developer and publisher of the app using the Approov SDK (developer) is distinct from the publisher of the API that is protected by Approov (controller). Both the developer and the controller must have Approov accounts. The developer is responsible for managing app registrations. The controller is responsible for Adding API Domains and also Managing Pins. Only the controller is able to view and manage the secret keys associated with their APIs.

To use this flow, an admin role holder of the controller account should create a delegate user role for use by the developer. The developer can then use this role to:

  • download the controller’s Initial SDK Configuration for use in their apps
  • add and remove registrations of their apps to and from the controller’s account. (They do this by cloning app registrations from their account into the controller’s account. Apps that were previously registered but have since been deleted by the developer are removed from the controller’s account at that same time that the new ones are added. The developer cannot modify any app registration that they did not add to the controller’s account. The controller can always remove any app registration from their own account.)

The developer uses the configuration obtained from the controller’s account to initialize the SDK in the app. Since the account that the app uses depends on the SDK configuration with which it is initialized, this flow means that the Approov SDK will use the controller’s account when it is obtaining tokens to include on its API requests. Typically, the app will provide a way to dynamically select which initial configuration is used, allowing the app to either use the developer’s or the controller’s account. In general, there might be several possible controller accounts for a single app.

While in app development, the developer can use Approov in the normal way using their own Approov account. When they do a release for use with the controller’s APIs, either for testing or production, then they will need to copy the active app registrations from their account into the controller’s account. In the case where a single app is to be used by various controllers, the app developer will need a delegate role provided by each one of those controller accounts. If the app has the ability to dynamically switch which controller account is to be used, then the SDK must be reinitialized dynamically to select the appropriate one.

If the developer has initialized the delegate role(s) into their Approov CLI then the registrations can be cloned as follows:

$ approov registration -cloneToAllDelegateAccounts
registrations will be cloned to the following accounts:
  accountA
  accountB
WARNING: this will have an immediate impact on production of the target accounts. If you wish to continue then please enter YES and return: YES
cloning 3 permanent registrations into account accountA
cloning 3 permanent registrations into account accountB

If the delegate roles are password protected then you may be asked for each of the passwords during the cloning operation. If you are unable to provide the correct password then the cloning for that particular account is skipped.

In the example, three registrations are cloned to two different accounts. Note that only permanent registrations are cloned. Note also, due to the complete cloning of all active app registrations, if a new API controller account is introduced, with a new delegate role, then all registrations (including historic ones) are easily cloned with this single command. If a registration was previously cloned, but then subsequently removed, then the next clone operation will also remove it from the target delegate account.

When the registrations are listed in the delegate account they are associated with the name of the app developer account from which they were cloned. This allows the API controller to easily identify the apps that were contributed by different delegate roles.

If you only want to clone to a subset of all your delegate role accounts, then you can do this as follows:

approov registration -cloneToAccounts accountA
registrations will be cloned to the following accounts:
  accountA
WARNING: this will have an immediate impact on production of the target accounts. If you wish to continue then please enter YES and return: YES
cloning 3 permanent registrations into account accountA

This option takes a comma seperated list of the accounts into which you wish to clone your registrations.

The maximum number of registrations that may be cloned in this way is 50. A warning is provided if the maximum number of registrations in the target account is exceeded.

This command only clones the app registrations. If you are using Android App Bundle registrations then you will also need to set the app signing certificate in the target account. The delegate role provides rights to do this. Note also that if you are relying on device check or safety net this information can also be set using a delegate role.

If your app uses the bitcode version of an iOS SDK then you must obtain the same version of the bitcode SDK in all of the delegate accounts. This automatically updates some aspects of the security settings of the account to be compatible with bitcode usage.

Approov Tokens

The result of performing a token fetch request with the Approov SDK is an Approov token held by the app. The app then adds the token to the requests made to the backend API to be used in the authorization flow. This section describes the format and content of the tokens.

Token Format

The Approov service uses JSON Web Tokens (JWTs) to represent the authenticity of client apps. This in an open and standard mechanism for representing claims in a tamper proof form and your web service will need to decode and verify these tokens as part of the Approov flow. An Approov token is typically a JWS (a type of JWT) which consists of three parts; the header, payload and signature where each part is base64url encoded and the parts are separated by periods. For a more in depth explanation off JWT tokens, please read this introduction.

JWT libraries take responsibility for generating the header and the signature. We just need to specify the signing algorithm we want to use, the secret key for the algorithm, and the un-encoded payload part. For JWTs, the payload is always a JSON object with the entries referred to as claims.

JWS Token Signing

This section describes the approach used to create signed JWTs (called JWS to differentiate them from JWE tokens which are encrypted). If an app has passed the attestation process acoording to the selected rejection policy, then a correctly signed token is issued. If the rejection policy causes the app to fail attestation then a token is still issued, but it will not be correctly signed. An observer that does not know the signing secret key will not be able to differentiate between these two cases.

There are a number of different options for token signing depending on the type notified for the API domain when it is added:

  • account: This is the default, and this selects a token signed with the HS256 algorithm. This peforms HMAC signing using the account secret key. The 512-bit symmetric secret may be exported using the approov CLI. If there are multiple API domains using the account type then they are all signed using this key.
  • keyset: If keyset keys have been added then an API domain may be assigned to use one of them for token signing. Each key in the keyset is associated with a particular signing algorithm, providing support for asymmetric key pairs such as RSA and ECDSA.
  • restricted: Some specific domains are considered to be restricted and are managed directly by Approov (such as the demonstration Shapes domain). If these API domains are added to the account then they are automatically allocated the restricted type. Approov tokens for them are signed or encrypted using a different key that is not accessible.

Be aware of the performance impact when you are selecting your algorithm. Token signing is performed by the Approov cloud service and it impacts the time required to get a token. Token verification is performed by the backend that handles API requests. The precise performance for different algorithms will be specific to the implementation you use and the hardware on which it is running, however, you can use the table below as a rough guide for Approov tokens (using an HS256 base-case with a signing time of x):

Algorithm Signing Verifying
HS256 x 2x
ES256 5x 15x
RS256/PS256 250x 10x

JWE Token Encryption

Note that Approov can also support another type of JWT, encrypted JWE tokens. Typically these only need to be used in conjunction with the Offline Security Mode. However, they might also be used if you wish to provide extended information within the anno and do not want to reveal the contents to any party that is able to read the tokens. JWE tokens use compact serialization which has 5 parts separated by ., where the first part is unencrypted and holds the encoded information about the algorithms used to encrypt the Content Encryption Key (CEK) and the payload. The Approov service uses A256GCMKW (alg claim) for encrypting the CEK and A256GCM (enc claim) for content encryption.

An API domain will use JWEs if the -jwe option is used when adding the domain. A JWE will also be used if a keyset key is used that is associated with the A256GCMKW algorithm.

Token Lifespan

The normal lifetime for an Approov token is 5 minutes, plus a grace period, from the point of issue by the Approov cloud service. The grace period of a few seconds is added to allow a valid token to be propagated and checked within a backend API system. If a particular device is identified as being risky in some way (such as it being rooted or jailbroken), then, independently of the overall security rejection policy that is set, it will receive a shorter lived 2 minute token instead of a 5 minute one. This forces the device to make more frequent checks as it receives tokens.

The app itself should never cache Approov tokens that it gets from the Approov SDK. Instead, a fresh call to fetchApproovToken or fetchApproovTokenAndWait should be made each time an Approov token is required. If a token has already been fetched, and is not yet expired, then it will be returned immediately. However, each fetch call does some basic app environment checking and, if issues are discovered, performs a complete attestation check to fetch a new token. Thus an Approov token lifetime should be considered to be up to 5 minutes, since any cached token may be discarded at any point.

Token Claims

Depending on the source of an Approov token (the main Approov service or the Failover) the claims it contains may vary. However, the expiry (exp) claim is always present. The details of the claims are provided in the table below:

Key Name Type Description
exp Expiry Number The only mandatory claim for Approov tokens. It specifies the expiry time for the token as a Unix timestamp.
did Device ID String This claim identifies the device for which the token was issued. This is a base64 encoded string representing a 128-bit device identifier. Note that this is not, strictly speaking, a device identifier as it is also influenced by the app identifier and may change if the same app is uninstalled and then reinstalled on the same device.
arc Attestation Response Code String This is an optional claim that encodes information about a subset of the device property flags and also whether the attestation was passed or failed. The claim is encoded in base32 and is typically 10 characters long (although it may be longer in some circumstances). This claim is not included by tokens from the failover.
ip IP Address String This holds the IP address of the device as seen by the Approov cloud service. It is provided in a human readable IP address format (in either IPv4 or IPv6 format). In practice this value can often change between the time a token is issued and the time it is sent to your backend, so you should never block if it differs, but you may include it as a signal that tokens have somehow been stolen and are being replayed. This claim is not included by tokens from the failover or if the IP Tracking Policy for the account has been set to none.
iss Issuer String An optional claim that is added if the issuer inclusion option is enabled. This provides the Approov account ID that was used to issue the token (suffixed with approov.io). It can be used as an additional layer of backend verification if signing keys are shared between multiple accounts. It indicates that tokens were issued from the expected Approov account. This claim may also be set to an explicit value for long lived Approov tokens. This flexibility is designed for use with server-to-server communication (which may only be signed with the account specific secret keys).
anno Annotation Embedded JSON This is an embedded JSON array of strings showing the list of flags that are set and are in the annotation set for the security policy that is selected. This allows additional information to be collected about the state of a particular device without necessarily causing an attestation failure. Note that if there are no possible annotations then this claim is not present at all. This claim is not included by tokens from the failover.
pay Payload Hash String An optional claim that is added if the protected app passes a token binding argument to the setDataHashInToken method. The claim value is set to the base64 encoded SHA256 hash of the provided payload string. This is typically used to bind an Approov token to some other data used by your app to enhance security (like a user auth token).
aud Audience String An optional claim that is added if the audience inclusion option is enabled. This provides the domain for which the token was issued. It can be used as an additional layer of backend verification to ensure that tokens intended for one domain cannot be used on to access a different one.
mskid Message Siging Key ID String This is an optional claim that encodes the ID of a key being used for Message Signing. This is only present in Approov tokens for which message signing is active. This claim is not included by tokens from the failover.
mpk Measurement Proof Key String An optional claim to provide the measurement proof key if a measurement has been requested by the SDK on the domain for which the token is issued. This is a base64 encoded 128-bit proof key value. Note that if measurement is being used, then JWE tokens will be used to keep this claim secret.
imh Integrity Measurement Hash String An optional claim to provide the integrity measurement hash if a measurement has been requested by the SDK on the domain for which the token is issued. This is a base64 encoded 256-bit SHA256 measurement value. Note that if measurement is being used, then JWE tokens will be used to keep this claim secret.
dmh Device Measurement Hash String An optional claim to provide the device measurement hash if a measurement has been requested by the SDK on the domain for which the token is issued. This is a base64 encoded 256-bit SHA256 measurement value. Note that if measurement is being used, then JWE tokens will be used to keep this claim secret.

Attestation Response Code

An Attestation Response Code (ARC) is a short alphanumeric code that is assigned to all Approov token fetch events and is embedded inside the received Approov tokens in the arc claim. The ARC encodes a subset of the device property flags of the device making the request. It also encodes whether a valid Approov token is being issued or not. This is the preferred way of finding out why an attestation may have failed. In particular, this is invaluable for support situations when it is necessary to determine why a particular user is not receiving valid Approov tokens. It may also be useful for internal debug purposes or for tracking flags that are set on both valid and invalid tokens.

You can enable this option as follows:

$ approov policy -setARC on
WARNING: updating the arc policy will have an immediate impact on your apps in production. If you wish to continue then please enter YES and return: YES
arc policy was set successfully

Changing the ARC policy requires an admin role and confirmation.

Although you are able to set the arc policy to off we do not recommend this.

The current status of the ARC policy can be obtained as follows:

$ approov policy -getARC
ARC policy is on
flags that can be ARC encoded:
  app-not-registered
  bad-hmac
  ...

If the policy is on then a list of the device property flags that can be encoded in the ARC are provided. This means that if any of those properties were set for the Approov token fetch then you will be able to determine that from decoding the ARC.

Accounts created since the release of version 2.5 have this option enabled by default.

The codes are encoded using a cryptographic secret so that it is not possible to determine their meaning without access to the Approov account backend. Moreover, the encoding for each Approov account is unique so codes generated by one account cannot be decoded by another.

Getting an Attestation Response Code

The Attestation Response Code is embedded in the arc claim of all issued tokens. However, if you wish to obtain the code directly then a method in the SDK is provided that is available once an Approov token is fetched. This is available even if the Approov token is a JWE and thus encrypted. Use the following call:


String arc = approovResult.getARC();

let arc = approovResult.ARC

If the Approov token fetch was unsuccessful, or the ARC capability is not enabled, then an empty string is returned. Otherwise the short base32 encoded ARC string is provided. It is safe to include this in logging, since without access to the Approov backend it is not possible to decode its contents.

The ARC can be provided in error information presented to the user or submitted by the app in an API call, for cases where the user is having trouble using their app. The base32 encoding and short length means that it is possible to read out or submit this information reliably for support purposes. The encoding also includes internal checking that detects most transcription errors. This facility might be needed if the app is not usable because invalid Approov tokens are being issued. When the ARC is decoded it is then possible to ascertain why Approov token fetches are failing and for remedial action to be taken.

This method is only available in version 2.5.0 and later SDKs.

An API endpoint is provided that takes an ARC and returns the decoded information for it. This is designed for use in backend customer support systems. Information about how to access the API endpoint is provided as follows:

$ approov token -showArcInfoCurl
curl -H "Authorization: Bearer xxx..." -H "Arc: <arc>" https://<account-domain>/arc-info/

The API key in the Authorization is account specific and should not change unless a specific support request is made to request its rotation. The API key only allows the decoding of tokens and obtaining additional token information and does not enable any other actions on the account. However, as with any account credential, steps should be taken to keep it secured and to prevent accidental disclosure or inclusion in source code repositories.

An example API request is made as follows, with the ARC XJEUXVAKZY:

$ curl -H "Authorization: Bearer xxx..." -H "Arc: XJEUXVAKZY" https://<account-domain>/arc-info/
{
  "status": "failed",
  "deviceProperties": [
    "app-not-registered",
    "rooted",
    "root-risk",
    "xposed"
  ]
}

The status indicates if the attestation was passed or failed. If the provided ARC is invalid in some way (perhaps issued to a different Approov account or entered incorrectly) then the status will be arc invalid.

The deviceProperties lists device property flags that have been determined from the device. If the status is failed then this will almost certainly pinpoint the reason(s).

Note that, although the output is a curl command, you can of course use an alternative tool or command to perform the GET request.

This API is for the use of your backend systems only. Never build calls to this API, and especially not the Authorization key required, directly into your mobile app. Moreover, this endpoint should only be used for informational purposes, as it may be subject to rate limiting and does not have the Cloud Server Redundancy features of the Approov token issuance process.

You should never use this endpoint to check the validity of the token. Always check validity by verifying the signature of the Approov token directly. This endpoint should only be used for informational purposes on a subset of received tokens; it may be subject to rate limiting and does not have the Cloud Server Redundancy features of the Approov token issuance service.

Obtaining Additional Token Information

An API is provided that allows additional information to be obtained for a previously issued Approov token. Note that for additional information to be available the Attestation Response Code feature must be enabled.

Information about how to access the API endpoint is provided as follows:

$ approov token -showTokenInfoCurl
curl -X PUT -H "Authorization: Bearer xxx..." -H "Approov-Token: <token>" https://<account-domain>/token-info/
  add `-H "Report-Message: <message>" to report a particular token

The API key in the Authorization is account specific and should not change unless a specific support request is made to request its rotation. The API key only allows the decoding of tokens and obtaining additional token information and does not enable any other actions on the account. However, as with any account credential, steps should be taken to keep it secured and to prevent accidental disclosure or inclusion in source code repositories.

You should provide an issued Approov token to the API endpoint, for example:

$ curl -X PUT -H "Authorization: Bearer xxx..." -H "Approov-Token: eyJh..." https://<account-domain>/token-info/
{
  "did": "qZka0yfv+ExvOq3PRh6pGw==",
  "status": "failed",
  "claims": {
    "arc": "B3Y5SLMO2K",
    "did": "qZka0yfv+ExvOq3PRh6pGw==",
    "exp": 1607528162,
    "ip": "1.2.3.4"
  },
  "expiryTime": "2020-12-09 15:36:02 UTC"
  "deviceProperties": [
    "app-not-registered",
    "rooted",
    "root-risk",
    "xposed"
  ]
}

The status indicates if the attestation was passed or failed. If the provided token was issued to a different account then the status is likely to be arc invalid (and if it does happen to be valid it will not report the correct decoding). The did property provides the Device ID. The full set of token claims are provided, even if the Approov token is an encrypted JWE. The expiryTime provides a readable form of the expiry time of the Approov token. Note that, the tokens you provide may have expired and this will not impact their status or the ability to decode them.

The deviceProperties lists the device property flags that have been determined from the device. If the status is failed then this will almost certainly pinpoint the reason(s).

Note that although the syntax is provided for curl for your convenience, any standard tool or mechanism can be used to perform the PUT request to the endpoint.

This API is for the use of your backend systems only. Never build calls to this API into your mobile app and, especially, never expose the Authorization key.

You should never use this endpoint to check the validity of the token. Always check validity by verifying the signature of the Approov token directly. This endpoint should only be used for informational purposes on a subset of received tokens; it may be subject to rate limiting and does not have the Cloud Server Redundancy features of the Approov token issuance service.

Reporting Token Misuse

The Token Information endpoint provides an optional facility to report the misuse of particular tokens. This endpoint can be used in conjunction with Approov support to allow automatic reporting of tokens that appear to be being misused in some way. This may be because you have reason to believe that a valid Approov token is being issued when it should not have been. Alternatively, if you believe that the Approov token has been somehow extracted from a running app and is being used to make API calls outside of the official app then these should be reported.

You should include a short message (256 characters or less) describing the issue in the Report-Message header for the request, for example:

$ curl -X PUT -H "Authorization: Bearer xxx..." -H "Approov-Token: eyJh..." -H "Report-Message: Expected a token fail on this device, contact ops@mydomain.com" https://<account-domain>/token-info/
{
  "did": "qZka0yfv+ExvOq3PRh6pGw==",
  "status": "failed",
  "claims": {
    "arc": "B3Y5SLMO2K",
    "did": "qZka0yfv+ExvOq3PRh6pGw==",
    "exp": 1598608042,
    "ip": "1.2.3.4"
  },
  "deviceProperties": [
    "app-not-registered",
    "rooted",
    "root-risk",
    "xposed"
  ]
}

Token reports are automatically forwarded to Approov support and they will be notified at the end of day in which the report is made. Unless you are already in dialogue with Approov support about this issue, we suggest you include email contact information in your report message. Approov support will analyze the information provided, and may gather more information from the specific device reported, and will respond with some additional diagnosis of the issue.

Token reports are rate limited, typically restricted to one per minute. If you exceed the rate limit then the API will return Ok but the report will not be forwarded to Approov support. Note also that subsequent token reports are ignored if they are issued on the same day and about the same device ID.

Checking Token Validity

A checking option is provided that allows any Approov token to be checked. This is useful for debug purposes during your integration with Approov. Simply use:

$ approov token -check eyJhbGciOiJIUzI1Ni…
failed: expired alg:HS256 {"anno":["app-not-registered"],"did":"h4gubfCFzJu81j/U2BJsdg==","exp":1558626228,"ip":"1.2.3.4","pay":"6ZIvH1YelZyc2hx1iRRqD3dWNcFgjVtCon+7921XDjg="}

The Approov token content is decoded, and information is provided about whether the token is passed or failed. For a JWS it also shows if the token has expired or not. Remember that expiry and signature validity are independent. The validity of a token (i.e. whether it is signed with the account secret key) depends on whether the request came from a valid app instance and also the security policy in place in the account. The expiry is purely related to how long ago the token was issued. Tokens normally only have a 5 minute lifetime.

The signing algorithm of the token (alg) is also shown, as well as any key ID (kid) in the token.

The content of the decoded token will depend on other Approov features that are being used. This particular token is issued from an account with a non-default annotation policy, that provides some reasons why a token may be invalid, in the anno claim. It also has a pay claim as a result of using setDataHashInToken.

Note that if Attestation Response Codes are enabled for the account then this command will also provide a list of the device property flags associated with the device to which the Approov token was issued.

Note that the token check is also able to process encrypted JWE tokens. It shows if they are valid and can decode their content, even if they are invalid.

Loggable Tokens

It is generally not recommended to log Approov tokens within an app. This is because it might be possible for an attacker to turn logging on in a production app and use this as a mechanism to steal valid Approov tokens that have been received. Furthermore, the raw Approov tokens are also very opaque since they are just base64url encoded JWT strings and therefore not very useful for debugging.

A facility is provided in the SDK to get a “loggable token” from the result data returned from fetchApproovToken or fetchApproovTokenAndWait. This provides a decoded string form of the Approov token, and is therefore much more useful for debug purposes. The returned string holds a JSON object containing the payload contents with an additional sip claim, as demonstrated by the following example:

{
  "anno": [
    "app-not-registered"
  ],
  "did": "h4gubfCFzJu81j/U2BJsdg==",
  "exp": 1558626228,
  "ip": "1.2.3.4",
  "pay": "6ZIvH1YelZyc2hx1iRRqD3dWNcFgjVtCon+7921XDjg=",
  "sip": "HggK-u"
}

Note that if no valid token was returned from the Approov token fetch request, or the returned token was a JWE, then a marshaled JSON string giving the error is provided, e.g.:


{
  "error": "POOR_NETWORK"
}

{
  "error": "JWE"
}

As mentioned, a loggable token includes a special sip claim. This contains the first few characters of the signature of the token. Six characters are provided in base64, giving 36 bits out of the 256 bits provided in the complete signature. Thus it is not sufficient to create a validly signed token, but, if the signing key is known, it is sufficient to check, with a very high degree of accuracy, whether an Approov token is valid. Note that app itself never knows the symmetric secret used for signing tokens. Its possible to check a loggable token in the same way as a JWT as follows:

$ approov token -check '{"anno":["app-not-registered"...'
failed: loggable

Note that the loggable token must be enclosed in single quotes so that it is treated properly as a single command line parameter.

A statement is provided about whether the token was valid or not. It does this by reproducing the complete Approov token on the cloud service with the correct signature and then checking this against the prefix part of the signature that it knows from the sip.

The sip claim cannot be used to determined token validity if the token was signed with a the probabilistic signature scheme. Probabilistic schemes include keyset key that use one of the following algorithms: PS256, PS384, PS512, ES256, ES384 or ES512. For these algorithms the loggable token will always be interpreted as a fail.

If you are using a version of the SDK prior to 2.2.0 and have enabled Key IDs, attempting to get a loggable token will result in a BAD_JWT_HEADER error.

Long Lived Approov Tokens

It is possible to generate Approov tokens that have a long expiry time. Approov tokens issued via the Approov SDK only have an expiry time of 5 minutes or less. This facility allows tokens for an arbitrary duration to be created. It requires an admin role. To create one use:

$ approov token my-admin.tok -genLongLived server-token,90d
token will expire at 2019-06-03 13:24:38
WARNING: Long lived token should never be integrated into public clients and their security must be carefully managed
eyJhbGciOiJIUzI…

This generates an Approov token that is valid for 90 days. The server-token parameter is included in the iss claim of the token. Change this to whatever name you would like. It can be used to identify particular long lived tokens, or even to revoke certain ones by backend API checking. In effect this claim could be used as a type of API key within the overall signed Approov token. The expiry time should be specified in days and cannot be less than 1 day.

The generated Approov token can be checked and decoded as follows:

$ approov token -check eyJhbGciOiJIUzI…
passed: alg:HS256 {"exp":1567078473,"iss":"server-token"}

Long lived tokens can be used to authorize communication to the protected backend API for server-to-server communication and test environments (such as Postman). This allows a particular API to be accessible both from mobile apps and also via other servers without having to create a different authorization mechanism. Generating a long lived token has no impact on the expiry time of tokens issued normally through the Approov SDK.

Long lived tokens must never be included in public clients, such as web pages or mobile apps. They should only be used in circumstances where the token can be protected in a server environment.

Long lived tokens cannot be generated for restricted domains, such as shapes.approov.io demo endpoint. Moreover, it is only possible to generate long lived JWS tokens signed with the account secret key. It is not possible to create tokens signed with a keyset key.

IP Tracking Policy

The IP tracking policy determines how Internet Protocol addresses are dealt with in your Approov account. When your account is setup the policy will be token. This means that the IP address of the device requesting an Approov token will be included in the token itself in the ip claim. However, in accordance with Approov’s privacy notice, no record will be kept of the IP address in Approov’s internal logs or records. This is because IP addresses can be considered to be Personally Identifiable Information (PII) and the Approov service does not collect this by default for an account holder’s end customers. IP addresses are only stored by Approov services after transformation through a one-way hash function from which the original IP address cannot be recovered.

If desired the IP tracking policy can be changed to none so that the IP address claim is not even included in the issued Approov token.

$ approov policy -setIPTracking none
WARNING: updating the IP tracking policy will have an immediate impact on your apps in production. If you wish to continue then please enter YES and return: YES
IP tracking policy was set successfully

An admin role and confirmation is required to make an IP tracking policy change.

A policy of full is also available whereby permission is given for Approov services to record unhashed IP addresses. This allows more sophisticated correlation analysis between IP addresses and device characteristics, carried out in conjunction with Approov support. Note, however, that if this option is used then the Approov service is collecting PII on your behalf and this may have GDPR implications.

The current IP tracking policy can always be retrieved as follows:

$ approov policy -getIPTracking
IP tracking policy is none

Audience Inclusion

The audience inclusion feature allows the aud claim to be populated in all Approov tokens issued for the account. This will be set to the domain name for which the Approov token was issued. This can be useful to ensure that tokens issued for one domain cannot be used to gain access to a different domain that shares the same signing secret key. This needs to be checked by the backend API integration.

The audience inclusion feature can be enabled as follows:

$ approov policy -setAudience on
WARNING: updating the audience policy will have an immediate impact on your apps in production. If you wish to continue then please enter YES and return: YES
audience policy was set successfully

An admin role and confirmation is required to make an audience policy change.

The current audience policy can always be retrieved as follows:

$ approov policy -getAudience
audience policy is on

Issuer Inclusion

The issuer inclusion feature allows the iss claim to be populated in all Approov tokens issued for the account. This will be set to the name of the account suffixed with approov.io. This is useful as an additional verification if signing keys are being shared between multiple accounts. The backend API integration is able to verify that the token was issued for the expected account.

The issuer inclusion feature can be enabled as follows:

$ approov policy -setIssuer on
WARNING: updating the issuer policy will have an immediate impact on your apps in production. If you wish to continue then please enter YES and return: YES
issuer policy was set successfully

An admin role and confirmation is required to make an issuer policy change.

The current issuer policy can always be retrieved as follows:

$ approov policy -getIssuer
issuer policy is on

Backend Integration

This section describes the changes that are needed in the backend API to check that an Approov token is valid.

This section provides a detailed reference for backend integrations. If you able to use one of our Quickstart Backend Integrations then you may find this simpler.

Requirements

To protect a backend API with Approov it is necessary to check that incoming requests have a valid Approov token. This might be required on all endpoints or just on some that demand additional security. Typically, token checking will be performed in some middleware layer of the backend rather than be implemented in the business logic.

Approov token checking is often performed in addition to user authorization, as an orthogonal activity. User authentication and authorization ensure that a known user is invoking the software making the request. Approov checking ensures that the software making the request is actually what it claims to be.

Approov uses standard JWTs as discussed in the previous section. This makes the backend API checking straightforward since almost all backend languages and technologies support JWT checking. To check an Approov JWS, the account secret key must be made available to the backend code. The token will be signed with the HS256 profile, and the shared symmetric account secret key is needed to perform the check. Libraries for working with JWTs are available in most common languages, with many listed on the JWT homepage.

There are essentially three cases which should cause a request to be rejected:

  • Invalid Token: If the Approov token is simply missing or is not a correctly formatted JWT then this indicates some spoofed request and should be rejected.
  • Incorrectly Signed Token: If the token is not correctly signed then it must be rejected. Obviously an attacker can synthesize an incorrectly signed token. An app is also provided with an incorrectly signed token if the attestation has been rejected. Note it is important to ensure that the signing method of the JWT is HS256.
  • Expired Token: Any token that has expired must be rejected, as under normal operation this should never happen. The app should never cache the Approov token, and the Approov SDK never provides a token that has expired. A small grace period is built into the token lifetime to allow for transmission and propagation delays in the backend systems. It is important to make sure that the server checking the tokens is correctly time synchronized.

Note that the actual behavior for an invalid token does not have to be rejection, although this is the typical approach. An invalid token event could simply be used for logging or as a signal to require some additional authentication and security checks on a particular user.

We recommend that the backend integration has a dynamic facility to enable or disable the Approov token check. This allows traffic to be passed through without the check in case of some emergency situation. Moreover, you may wish to collect logging for events where invalid Approov tokens are being provided.

Account Secret Key Export

The account secret key can be obtained with the following command:

$ approov secret -get base64
note: secret is base64 encoded and must be decoded to its binary form to verify Approov tokens
dEitzKUYJLQ…

An admin role required to gain access to the account secret key.

This example displays the secret as a base64 encoded string, representing a 512-bit value that is randomly assigned to the account during signup. The value of the secret must be protected with extreme care. The number of individuals with exposure to the value of the secret should be minimized and it should never be checked into a source control system. Ideally, it should only be made available to the runtime environment of the backend servers. Note that if base64url is used as a parameter to the command then the secret can be obtained in base64url encoded format, which may be needed by some backend integrations.

Note that it is also possible to obtain the secret in raw form, as discussed here.

If you wish to output the secret value, with no additional text, you may use the -plain option. This allows the output to be easily piped into other command line tools, so that generic scripts can be easily developed that extract and operate on the account secret key. Of course, you should never include your administration token in such a script directly.

If you wish to export the secret key that is used for JWE tokens (of the account type and using the A256GCMKW algorithm) then the -jwe option can be used as follows:

$ approov secret -jwe -get base64
note: secret is base64 encoded and must be decoded to its binary form to verify Approov tokens
1bgyVw6/9X6...

Account Secret Key JWK Export

The account secret key may also be exported in JSON Web Key (JWK) format as follows:

$ approov secret -getJWK secret.jwk
JWK written to file secret.jwk

This writes the JWK to the file secret.jwk as follows:

$ less secret.jwk
{
    "kty": "oct",
    "use": "sig",
    "k": "dEitzKUYJLQ…",
    "alg": "HS256"
}

The JWK format is useful for certain backend systems that accept this format directly. Usage with JWKs is also often associated with the requirement for a Key ID property in tokens. This needs to be set prior to getting the JWK so that the kid property is listed.

It is also possible to export it in the JSON Web Key Set format, for systems that require that format. In this case the single account secret key is included in the keys map.

If the -jwe option is used then the secret key used for JWEs is provided, rather than the one for JWSs.

Generating Example Tokens

It is possible to generate example Approov tokens that have the same format as those generated for a mobile app. For example:

$ approov token -genExample my.api.io
eyJhbGciOiJIUzI1N…

The API domain, for which the token is being generated, must be provided in the same way that the app provides it for a call to fetchApproovToken. The result is a valid token that lasts for one hour. The extended expiry time of these tokens provides for longer debug sessions using a single token. For example, the token can be used in synthetic queries made to a backend API to check that it is working correctly. There is no need to know the actual account secret key to use this facility as the token is automatically signed with the correct secret.

If an API domain is provided that has not been added for the account then no token can be generated. If the API domain is associated with encrypted JWE tokens then one is generated, to allow verification of the JWE decryption logic in the backend.

The example tokens contain a fake IP address and device ID that are in the correct format. A -setDataHashInToken option is also provided for testing the Token Binding feature. You can decode the example Approov token to see what it contains:

$ approov token -check eyJhbGciOiJIUzI1N…
passed: alg:HS256 {"did":"ExampleApproovTokenDID==","exp":1558980988,"ip":"1.2.3.4"}

By default a valid Approov token is generated. But it is also possible to generate an invalid token to test the backend API handling with such tokens. For instance:

$ approov token -genExample my.api.io -type invalid
eyJhbGciOiJIUzI1N…
$ approov token -check eyJhbGciOiJIUzI1N…
failed: alg:HS256 {"did":"ExampleApproovTokenDID==","exp":1558981918,"ip":"1.2.3.4"}

Changing the Account Secret Key

The account secret key can be changed with the following command:

$ approov secret -change
WARNING: updating the account secret key will have an immediate impact on your apps in production. If you wish to continue then please enter YES and return:

This requires an admin role and a confirmation of the operation. If confirmed then the new account secret key value is output as follows:

new base64 encoded account secret key is VcXl2IgVUgz…

If the account secret key is changed then this has an impact in production within 30 seconds for newly issued tokens. This means that for a period of up to 5 minutes the backend API may see a combination of tokens signed with the old secret (if they have been cached and reused by the app SDKs) and new ones signed with the new secret (for freshly obtained tokens).

In general it is hard for a backend integration to deal with two different secret values, so we recommend the following procedure if rotating the account secret key:

  1. Disable Approov token checking on the backend API. This will let any traffic through for a short period of time,
  2. Execute the command to update the account secret key and copy the new value.
  3. Integrate the new account secret key into the backend API.
  4. Re-enable Approov token checking. Assuming this process takes more than 5 minutes, all tokens in use will be using the new account secret key.

Raw Account Secret Key

There are certain specific backend JWT checking libraries that require the secret to be specified as a raw string (they have no facility to provide it in an encoded form such as base64). To support this, a feature is provided to get the secret in its raw format. However, the initial secret generated for your account will almost certainly contain some bytes that are not printable and therefore cannot easily be added to a string. Thus, if you need the secret in its raw form, you must first change it and include the special -forcePrintable option as follows:

approov secret change -forcePrintable

It is then possible to obtain the raw secret value as follows:

approov secret -get raw

Use of this option reduces the entropy of the secret and so you should only use this facility if there is no option but to use a JWT library that requires the secret in this format. Typically you should specify the secret in an encoded format rather than a raw string.

Public Key Pinning Configuration

This section describes how certificate public key pins can be defined so that they can be made available in the initial and dynamic configuration of the apps using Approov. The next section deals with how the app can use this pinning information.

Background

It is essential that all of the channels over which Approov tokens may be transmitted use pinned connections. This means that the app should only be willing to establish a TLS connection where the presented certificates are both valid and where at least one public key of a certificate in the chain is specifically white listed (aka pinned), by the app itself, as being valid.

Pinning is necessitated by the fact that an attacker may be able to control both the device and also the channel over which it communicates. In the absence of pinning, attackers are able to install additional certificates on the device as being trusted, and then use a proxy to decrypt any traffic from the mobile app to the API endpoints. This method can then be used to steal valid Approov tokens from the communication channel in order to make spoofed requests, as though they were coming from the app.

Pinning represents good security hygiene. It prevents real users from having their traffic intercepted if an attacker is able to trick them into installing an additional certificate on their device that then becomes trusted for TLS communication. Pinning ensures that the app avoids completely delegating its trust to the device.

There are various existing mechanisms to implement pinning in an app. Although conceptually identical, there are significant implementation differences between Android and iOS:

  • Android: There is a good overview on TLS more generally here. This article provides specific information on how pinning can be implemented for various different HTTP stacks that might be used in an app. Recent versions of Android have also added a network security configuration feature that allows pins to be specified at the manifest level for an app. Pinning with the OkHttp stack is straightforward using the CertificatePinner class.
  • iOS: There are fewer resources targeting iOS, but this is a good place to start. TrustKit is a popular library used to implement pinning, and there is also a version for Android.

These standard methods can be used to pin an app’s connections with the backend API server.

Note that the Approov SDK uses its own methods to pin the connections it makes with the Approov cloud service, so you can be sure that this channel is defended without any further work.

Static Pinning Issues

Approov provides a dynamic pinning mechanism, discussed in the next section. This section discusses some of the limitations of traditional static pinning.

Under normal circumstances public key pins do not have to be changed very often. Approov uses public key pinning rather than certificate pinning. This means that the pin is actually to the public key of the certificate rather than a hash of the whole certificate contents. The advantage of this is that, if certificates are changed simply because they are expiring and need to be renewed, then the same public/private key pair may be used to generate the new certificate without invalidating the pins.

The difficulty arises when a certificate has to be revoked and replaced if there is a concern that the private key has been compromised (or lost). This could allow an attacker to generate fake certificates and spoof the endpoint, intercepting traffic from the app if they are able to insert themselves as a Man-in-the-Middle (MitM) in the network.

Such an event necessitates a change in the public key pin for the certificate, as a new private key needs to be generated. If this is simply changed immediately then it would prevent apps with the public key pin from connecting to the API. The app would no longer work. It is recommended practice to also include a backup pin inside in the app that could be used in such an emergency. But this requires careful management and also relies on the backup’s private key not being compromised at the same time.

Thus the disadvantage of the static pinning methods described in the previous section is that they fix the set of valid pins into the app itself as part of its configuration. This means that for an app to get a new set of pins a new version of the app must be released and be installed on a user’s device. In reality this can take many days, or even weeks, for most of the apps to update and there may always be a stubborn cohort whose apps are never updated. These would be denied access once the pins are changed, and may end up as either permanently lost users or ones which increase user support load.

Static pinning causes problems both with the speed of incident response and user retention. Ideally what is required is a means to transmit the updated pins over-the-air immediately to invocations of the app without any need for an app update. Moreover, this needs to be done in a secure manner to prevent an attacker using this as a back door to inject their own pins to undermine the pinning protection. Approov offers a dynamic pinning solution that fulfils these requirements and is described in the next section.

Approov Dynamic Pinning

Approov holds the set of public key pins for API domains being protected, inside the SDK configuration file. The initial SDK configuration is obtained and added into the app content. This means that the pins are available from this configuration as soon as the app starts with no need for network configuration. This is convenient for apps developed using frameworks that require any public key pins to be presented very early during the initialisation of the app. If the pins are changed then subsequent app registrations cause a warning message to be issued to update the initial configuration with the latest information.

The overall architecture is as follows:

Pinning Architecture

The SDK configuration is signed using Elliptic Curve Cryptography (ECC), with the public key held in the initial SDK configuration and the private key held securely in Approov’s servers. This allows over-the-air dynamic updates to the configuration to be sent to running apps that can be verified as being untampered and authentically issued by the Approov servers. This is guaranteed even if the update is transmitted over a channel already compromised by a MitM attack. An attacker cannot know the private key to tamper with an update. They could block an update of course, but only while they have control of all communication, so any other use of the app will cause an update to be received.

If any change is made to the API domains and their pins using the approov commands described here, then an updated dynamic configuration will be transmitted to all any app that requests a new Approov token. The dynamic configuration is signed with the ECC private key, preventing any possibility of tampering and proving that the update has been issued by the Approov servers. This updated dynamic configuration will be written to the local storage of the app, and will either have an impact next time the app is started or immediately, depending upon the implementation of the pinning in the app. This verified updated configuration usurps the settings previously available from the initial SDK configuration.

This dynamic pinning is primarily designed to protect the channels over which Approov tokens are being transmitted. However, there is no reason why it can’t be used to protect any domain that the app communicates with, even if no Approov tokens are transmitted. The only restriction is that there must be sufficient knowledge about how certificates will be presented on that endpoint so that there is notice if there is an upcoming change that may impact the public key.

The dynamic configuration update can also be used to perform over-the-air updates of the networking access rules (in terms of domain names and timeouts) that are used by the Approov SDK to access the Approov cloud servers.

Managing Pins

Any domain can have a list of pins expressed as subject public key info hashes in base64. A pin is considered to have passed if any part of the certificate chain includes one of the pins provided. Thus intermediate public key pins are supported. Backup pin(s) can also be included if desired.

Facilities are provided for extracting the public keys of certificates directly, or live from existing endpoints. Certificate extraction allows pins to known prior to certificates going into service, so that the pins can be added to the Approov server configuration ahead of time as additional pins. Ideally this should happen some time before the new certificate is about to go live. This ensures that there is absolutely no interruption of service to the app since it will have already received the configuration update prior to the certificate changing.

If the app is able to receive a new configuration update and immediately change the pins being used, then the update only needs to occur early enough that any prior Approov token fetch will have received the configuration revision. This only needs to be 5 minutes. In other cases, where the app cannot immediately update its pins on receipt of a new configuration, then a longer time period is required. This will depend on the circumstances in the app but it is generally advisable to push out a new configuration some days ahead of the actual change.

Note, once a change has been completed, any redundant pins can be removed in a new configuration. If they were rotated due to a breach then this is especially important, since we no longer want the app to trust the pin.

Pinning For New API Domains

When a new API domain is added to the set of APIs, a pin for accessing that domain is automatically added. This is the pin extracted from the leaf certificate presented by the domain’s server:

$ approov api -add mydomain.com
WARNING: adding the API will have an immediate impact on your apps in production. If you wish to continue then please enter YES and return: YES
added new API domain mydomain.com with type:account, alg:HS256, pin:JG29gD8vWiEanTCVPjYLQ5yiYMKQqR05OH38yFf0kBU=
enabled continuous monitoring for https://mydomain.com:443 (remove using `approov monitoring -removeAPI`)

We strongly advise you to implement pinning for the API domains you access in your app. This means that any communication with this particular domain will be pinned to the value shown. In some cases it might not be appropriate to pin to the leaf certificate value, perhaps because different certificates may be presented by different servers on the endpoint. You must verify the stability of the provided pin with the backend API implementation team before going into production. If the pin changes, then your app will no longer work until a new set of pins can be pushed out, using the dynamic configuration update mechanism.

It is possible to change the pin type so that no pin is added at all with the new API domain:

$ approov api -add mydomain.com -pinType none
WARNING: adding the API will have an immediate impact on your apps in production. If you wish to continue then please enter YES and return: YES
added new API domain mydomain.com with type:account, alg:HS256, unpinned

When a leaf pin is being collected, it is obtained from both a local network request and via a network request from the Approov cloud servers. The pin obtained must match, or else an error is generated, for example:

$ approov api -add mydomain.com
domain mydomain.com local pin 1O0wDRM/roe6UTctDVQ5aN/ASNYsGQFVzXYhO34t5GE= differs from remote pin OfxtkIyzmWFXb028KrIr3VqP0XHW41mbunxtNnS3eb4= (may be due to local firewall)

This means that the observations differ. This might indicate that the leaf certificate obtained is not deterministic, or may depend on the geographic location from where the request is made. Alternatively, it might just mean that the local network is subject to interception via a firewall (this can be checked with the approov pin -api <domain> -getCertChainPins command which obtains the full certificate chain obtained from a local request).

If you are confident that either the localor remote public key pin is the one required then the appropriate one can be selected using the -pinType option. E.g.

$ approov api -add mydomain.com -pinType remote
added new API domain mydomain.com with type:account, alg:HS256, pin:OfxtkIyzmWFXb028KrIr3VqP0XHW41mbunxtNnS3eb4=
enabled continuous monitoring for https://mydomain.com:443 (remove using `approov monitoring -removeAPI`)

This selects the remote public key pin. Note that of course this means that the mobile app will not be able to run on the local network.

When you add new APIs, or change the pins on existing APIs, a new pinning configuration is automatically sent to your running apps when they connect to the Approov servers. This is because the initial configuration provided to your app will be out of date. To indicate this you will see a init-config-outdated metric associated with your apps. You should always strive to update the initial configuration for your app each time you release it so that it has the correct information from launch. This is especially important if you are working with a framework that applies the pins on app launch only. Updating the initial configuration optimizes the pinning process and means there is no dependency on an update from the Approov server.

Managing Domain Pins

Once a particular domain has been added it is then possible to add or remove pins on that domain. An individual domain may have up to 10 different pins specified for it. A connection attempt for domain is considered to be successful if any of the specified pins is present at any level in the certificate chain obtained from the API domain server. Thus leaf and intermediate certificate pins may be specified, along with backup pins which may not yet be in service. Note that if no pins are specified for a domain then this means it is unpinned and any certificate (presuming it meets the normal criteria) is deemed acceptable.

You can add a pin to a domain with the following command. The pin value itself may have been extracted using one of the methods discussed in the following sections. For example:

$ approov pin -api mydomain.com -add Q62DnTGJsy1h+ude8HB5ZjKy0Vhg2pvTzjplWSD3hkk=
WARNING: updating the pins will have an immediate impact on your apps in production. If you wish to continue then please enter YES and return: YES
pin Q62DnTGJsy1h+ude8HB5ZjKy0Vhg2pvTzjplWSD3hkk= added to API domain mydomain.com

Note that you need an admin role to modify the pins. You can see the pins set for any domain as follows:

$ approov pin -api mydomain.com -list
Q62DnTGJsy1h+ude8HB5ZjKy0Vhg2pvTzjplWSD3hkk=

Finally, specific pins can be removed as follows:

$ approov pin -api mydomain.com -remove Q62DnTGJsy1h+ude8HB5ZjKy0Vhg2pvTzjplWSD3hkk=
WARNING: updating the pins will have an immediate impact on your apps in production. If you wish to continue then please enter YES and return: YES
removed pin Q62DnTGJsy1h+ude8HB5ZjKy0Vhg2pvTzjplWSD3hkk= from API domain mydomain.com

Any attempt to change the pins for the demo endpoint shapes.approov.io result in an error.

Leaf Public Key Pin Extraction

The public key pin for a leaf certificate presented on a particular domain may be obtained as follows:

$ approov pin -api shapes.approov.io -getLeafPin matching
matching leaf pin for domain shapes.approov.io:443 is JG29gD8vWiEanTCVPjYLQ5yiYMKQqR05OH38yFf0kBU=

This obtains the same pin that would be obtained by the -addoption described above. The possible values for the parameter are as follows:

  • matching: Ensure that there is a matching pin between the local network access and remote observation by the Approov servers.
  • local: Obtain the pin value as observed on the local network.
  • remote: Obtain the pin value as observed remotely by the Approov servers.

Note that if the endpoint being accessed is not on the standard port of 443, the -port option can be used. Here is an example that gets the leaf pin as observed by the local machine on port 8000:

$ approov pin -api mydomain.com -getLeafPin local -port 8000
local leaf pin for domain mydomain.com:8000 is 0vNoWx4vRXJCQggeFuEx6/5yyhXVl/VScIN18PmL7co=

Only a single set of pins can be associated with a particular API domain, independently of the port that is being used. If the application uses multiple different ports on the same API domain, associated with different pins, then the overall domain only needs to be added once and the set of pins for it should be the union of all those required on the different ports.

Intermediate Public Key Pin Extraction

In some cases you might not want to pin against a leaf certificate but, instead, choose to pin against an intermediate certificate within the whole chain presented on a domain. A command is provided to extract this information:

$ approov pin -api shapes.approov.io -getCertChainPins
pin JG29gD8vWiEanTCVPjYLQ5yiYMKQqR05OH38yFf0kBU=, expiry 2020-05-22, CN=shapes.approov.io
pin JSMzqOOrtyOT1kmau6zKhgT676hGgczD5VMdRMyJZFA=, expiry 2025-10-19, CN=Amazon,OU=Server CA 1B,O=Amazon,C=US
pin ++MBgDH5WGvL9Bcn5Be30cRcL0f5O+NyoXuWtQdX1aI=, expiry 2037-12-31, CN=Amazon Root CA 1,O=Amazon,C=US
pin KwccWaCgrnaw6tsrrSO61FgLacNgG2MMLq8GE6+oP5I=, expiry 2034-06-28, CN=Starfield Services Root Certificate Authority - G2,O=Starfield Technologies\, Inc.,L=Scottsdale,ST=Arizona,C=US

This shows the full chain of certificates. In this example we use our demo endpoint shapes.approov.io that is hosted with AWS and uses an AWS issued certificate. You can see the chain right up to Amazon’s root certificate. Notice that certificates higher in the chain tend to have longer expiry times. Depending upon your particular backend setup it may be better to pin to one of these certificates rather than the leaf, which is more subject to change. Of course you need to ensure that any certificate you pin to cannot itself be used to sign certificates that an attacker might use. So, in general, try and pin as low in the overall chain as is practicable.

Note that if the endpoint being accessed is not on the standard port of 443, the -port option can be used to obtain the certificate chain on the specified port.

Note that the certificate chain is determined by making a local request. If the local network has a firewall that intercepts TLS traffic, then the resulting chain will not be the same as one observed by a device outside that network. Also be aware that, depending upon the backend API architecture, the observed chain may be influenced by the specific server that responds to the request. For example, different geographical regions may supply different certificates.

Certificate File Pin Extraction

As well as getting the public key pin from a live endpoint, it is also possible to get a pin from a certificate file. This is useful when you want to add a pin to a certificate that is not yet in service. Use the following to get the pin:

$ approov pin -getCertPin mycert.crt
pin jZetC3373f9dmwxg5YE9TCZzl4MYvp0eYTiEsbcTU34=, expiry 2020-05-10, CN=mydomain.com

This provides the public key pin along with the expiry time and subject of the certificate. Note that, to use this option it is necessary to have a PEM encoded certificate file. This is normally associated with a .cer, .crt or .pem file extension.

Certificate Pins From a Device

It is possible to obtain the set of pins seen by the SDK in a particular device using the Managing Devices capabilities.

Firstly you need to set the device ID from which you wish to capture the certificate information. To obtain the ID see Extracting the Device ID. A probe URL is specified that must include https and may optionally include a port number as shown:

$ approov device -add qZka0yfv+ExvOq3PRh6pGw== -probeURL https://shapes.approov.io:443
successfully set device qZka0yfv+ExvOq3PRh6pGw==

The next time the device fetches an Approov token it will also probe the specified URL and obtain the information about the certificate chain. Remember that the device must obtain a new Approov token to do this, so if it has already obtained one then it can be up to 5 minutes before it expires.

The device information can then be obtained as follows, and this should include the probe result information (other information has been elided here):

$ approov device -getInfo qZka0yfv+ExvOq3PRh6pGw==
captured: 2020-07-23 09:54:46 BST
... 
probe-result:
  probe result for https://shapes.approov.io:443:
   dqP5GOntRqZST5GfBj8NGpr1GMUTeKZG5g6+Q5mZFYM=: CN=shapes.demo.approov.io
   YLh1dUR9y6Kja30RrAn7JKnbQG/uEtLMkBgFF2Fuihg=: CN=Let's Encrypt Authority X3,O=Let's Encrypt,C=US
   Vjs8r4z+80wjNcr1YKepWQboSIRi63WsWXhIMN+eWys=: CN=DST Root CA X3,O=Digital Signature Trust Co.

This is the full set of certificate pins in the chain and the subject information of the certificate. The individual pins can be added via Managing Domain Pins.

This option of extracting the pins live from a running device is useful for pin debugging purposes, or network topologies where it is not practical to run the approov command line tool on the same network as the device and the network is not accessible via remote pin probing from the Approov cloud services. This might be the case if you are deploying Approov in a private network environment.

Forcing Pin Application

When pins are updated the latest versions are transmitted to all apps the next time they fetch an Approov token. To indicate a new configuration is available the isConfigChanged flag is set, as discussed in Reacting to Configuration Changes.

However, even if an app has received the latest configuration this does not necessarily mean that it is running with the latest pins applied. This is because some app frameworks only allow the pins to be set on the initial startup of the app. If an app has been running for some time then the pins it is using may be out of date. Normally updates do not force the app to restart to get the latest pins, as this would be detrimental to the user experience in most cases where an immediate update is not required.

A mechanism is provided to signal the need to force an immediate update where this is necessary. This is discussed in Reacting to Force Apply Pins. A command can be issued to force the current version of the APIs and their pins to be forced is as follows:

$ approov pin -forceApplyPins
WARNING: forcing pin application will have an immediate impact on your apps in production. If you wish to continue then please enter YES and return: YES
pin update has been forced

Any running app that has not read the latest pins with getPins receives a set isForceApplyPins flag next time it fetches a token. In the typical use case, new pins should be updated a couple of weeks before they go into service and then sometime later they can be forced. This procedure only results in a restart in the minority of apps that have not been relaunched for that period. In an emergency the forcing can be issued immediately. Note that this behaviour only impacts app integrations that are not able to dynamically update their pins.

Checking API Configuration

An option is provided that checks that all of the specified API domains are accessible and that, if pins are provided, then they do actually match a certificate being presented on the domain. This can be used as a quick check that the API configuration that is currently set is valid. It is invoked as follows:

$ approov api -check
mydomain.com: no pins defined
shapes.approov.io: matched pin JG29gD8vWiEanTCVPjYLQ5yiYMKQqR05OH38yFf0kBU=

The current API configuration is obtained from the Approov cloud service, and then each of the domains is checked from your local machine. If monitoring is enabled for the API domain then any port specified for that is used for the access. If the API domain is not accessible to obtain the certificates then that is considered an error. The command has a return code of 0 if it succeeded or 1 if it failed. Note that if the user role is invalid, or the Approov cloud service cannot be contacted, then this is not considered a failure since the explicit purpose of the command is to check the API endpoints themselves.

Getting All API Configuration

The complete set of API domains and the pins that have been added to the account can be extracted into a JSON format file as follows:

$ approov api -getAll apis.json
API domains and pins written to JSON file apis.json

This command gets all of the API attribute and pin information and writes it to the apis.json file. In this example the content is as follows:

$ less apis.json
{
  "mydomain.com": {
    "secretType": "account",
    "algorithm": "HS256",
    "pins": [],
    "monitorPort": 443
  },
  "shapes.approov.io": {
    "secretType": "restricted",
    "algorithm": "HS256",
    "pins": [
      "JG29gD8vWiEanTCVPjYLQ5yiYMKQqR05OH38yFf0kBU="
    ]
  }
}

This shows that Approov tokens can be issued either for mydomain.com or shapes.approov.io.

The attributes for each domain in the format are as follows:

  • secretType: The type of the API domain, primarily defining where the signing or encrypting secret key is obtained. Options are account, keyset, restricted or pinOnly.
  • algorithm: Provides the type of signing or encryption algorithm for the API domain (or empty for pinOnly).
  • kid: This is optional and provides any key ID for tokens issued for the domain. This is always present for the keyset type.
  • pins: The list of valid pins for the domain. Empty indicates that no pinning is applied.
  • monitorPort: If contiuous monitoring is enabled for the domain then this specifies the port being used (normally 443).

Setting All API Configuration

API configuration may be set in the same format as that obtained with the API -getAll option. New domains may be added, removed or edited. For instance, we may edit the JSON received in the previous section with a different domain and two different potential pins.

$ less apis.json
{
  "another.domain.com": {
    "secretType": "account",
    "algorithm": "HS256",
    "pins": [
      "/ABoW73P1I3gWumpugB6zzHtqjl0+yFKRBEvJW8I3sQ=",
      "Wp/PdTn4cw7/jwsS9+DnheEm5AbtTEsmVPAGOGY3tHk="
    ]
  },
  "shapes.approov.io": {
    "secretType": "restricted",
    "algorithm": "HS256",
    "pins": [
      "JG29gD8vWiEanTCVPjYLQ5yiYMKQqR05OH38yFf0kBU="
    ]
  }
}

We can then update the Approov server configuration as follows:

$ approov api -setAll apis.json
another.domain.com: matched pin Wp/PdTn4cw7/jwsS9+DnheEm5AbtTEsmVPAGOGY3tHk=
shapes.approov.io: matched pin JG29gD8vWiEanTCVPjYLQ5yiYMKQqR05OH38yFf0kBU=
WARNING: updating the APIs will have an immediate impact on your apps in production. If you wish to continue then please enter YES and return: YES
APIs set successfully

An error is generated if the input is not well formed JSON. Each of the domains provided are checked to see if they are reachable and if any one of the pins provided match. This ensures that the configuration is valid prior to updating it in the Approov cloud and distributing it to apps. If there is a problem then the follow message is seen:

WARNING: problem detected with APIs, we do not recommend you proceed (unless caused by known local firewall issue)

You can still choose to proceed if the issue may be caused by your local connectivity, since the check is made via the local network, but you should be convinced that this is the only issue or else it would be unwise to proceed.

We do not generally recommend that you use this option. It is better to perform finer grain management using the -add and -remove options for individual APIs and pins.

An admin role is required and further confirmation is expected. This is because these changes will have an impact on production within 30 seconds and as such are dangerous if domains have been accidentally removed or if pins are incorrect.

Any attempt to change the pins for the demo endpoint shapes.approov.io cause an error.

Public Key Pinning Implementation

The previous section described how the configuration can be managed to make use of the Approov dynamic pinning feature. This section provides examples of how the pins may be set using different languages and HTTP stacks.

This section provides a high level overview of pinning implementation and its testing. For details of the implementation for a particular http stack you should consult our Quickstart Frontend Integrations. Pinning is performed automatically as part of these integrations and we strongly recommend that you use these where possible.

Setting Pins

Pins can be set immediately after the Approov SDK has been initialized and any dynamic SDK configuration has been written. At this stage some pins will be available, either through the initial SDK configuration or through dynamic SDK configuration updates that have been received since the app was first installed.

This early access to the pins allows the pinning to be set up even for app development frameworks that require the information very early during the app startup. However, for these pins to actually have any impact in the app it is necessary to add code to communicate the pins to the TLS stack.

The SDK provides a getPins method that can be used by the app to obtain the currently configured set of pins to be used. The pins will be set up immediately after the initialization of the Approov SDK. The getPins method should be called with the parameter public-key-sha256, indicating the pinning type being performed. This specifies that the pinning type is the SHA256 hash of the Subject Public Key Information (SPKI) of the certificate. This is currenly the only type of pinning supported.

Reacting to Configuration Changes

Whenever an Approov token is fetched, a check should be made to see if a new dynamic SDK configuration has been received. This will happen for apps when a Pinning Configuration Change has been made in the account. The following code snippet shows how to perform this check and update, assuming that the approovResults variable holds the result of a token fetch:


if (approovResults.isConfigChanged()) {
    saveApproovConfigUpdate()
}


if approovResults.isConfigChanged {
    saveApproovConfigUpdate()
}

If a configuration update is received then this calls the saveApproovConfigUpdate method as defined here, or some equivalent for your app. This causes the new dynamic SDK configuration to be written to persistent storage so that it will be available before any network operations the next time the app is started.

A change to the SDK configuration is typically the result of some changes to the API domains and/or the pins that are set on them. Ideally, the app should react to those changes immediately by calling code to reset the pins associated with the APIs used by the app. The getPins method always returns the latest set of pins communicated to the app.

Whether immediate reactivity is possible, or architecturally easy to achieve, will depend on your app and the framework in which it is developed. Resetting pins typically requires a new pin configuration to be provided while constructing a new instance of the HTTP client used for making API calls. We recommend this as the best approach where possible, since it makes your app very reactive to any pin changes. In other cases, the app may only need to read the pinning information when actually making the TLS connection. In this case the app will always be reactive to the pin changes.

Reacting to Force Apply Pins

In some cases it is not possible for the app to immediately react to pinning changes. In this case the app may need a restart to apply the new pin configuration, or prompt the user to restart the app. Generally though we do not wish to restart the app every time there is a configuration change, as this could result in a poor user experience. Moreover, we may wish to push new pins to the configuration ahead of time so that they are more likely to be available when needed and thus avoid the need for an invasive restart altogether, since there is a higher chance of the app being restarted anyway.

One approach is to postpone any restart until there has been both a pending configuration update and a pinning failure exception has been caught by the app. That way a restart only occurs when absolutely necessary. Of course this may complicate the code by requiring special checks and logic on pinning failures.

Another mechanism is provided that is initiated by the Forcing Pin Application command. A flag is returned in the token fetch status:


if (approovResults.isForceApplyPins()) {
   ... 
}


if approovResults.isForceApplyPins {
    ... 
}

If this flag is set then it indicates that the last call to getPins made by the app obtained a version of the pins that is older than that which is being forced. Thus if an app has been naturally restarted since the last pin configuration update then it will already have a sufficiently recent version and the flag is not asserted,

The fact that these pins have been forced indicates that it is important that the new version is being used, perhaps because a certificate has been compromised or new pins are required to access an endpoint. If the flag is set then the app should take action to ensure that the pins are updated to the latest version, even if this means initiating an app restart. Calling getPins will reset the flag for the next time an Approov token fetch is made.

Testing the Pinning Implementation

It is important that any pinning implementation is tested, by forcing the app into situations where the pins are incorrect with respect to the certificates being presented on the API endpoints. It is necessary to show that this is handled correctly and, importantly, that dynamic configuration updates issued from the Approov cloud update the app’s pins correctly.

In production it would be undesirable to change the certificates on the real API endpoints to do the testing as this would impact all app users. To avoid the need to do this, Approov provides facilities to modify the set of pins provided to a particular device being tested. These facilities are discussed in detail in the Managing Devices section. The idea is that for a particular device the pins can be set to a known bad value that will trigger the pinning exception so that it can be tested, i.e. Approov changes what the app is pinning against rather than what is being presented by the API endpoint. This is an equivalently good test.

The following is a recipe of commands to perform a test on your pinning implementation. Firstly you will need to get the ID of your device, see Extracting the Device ID. You should then check that the app is operating normally and that you have pins defined for the endpoints you are trying to protect with pinning. You can check what pins are set using Getting Pin Configuration.

Next, you can block all of the communication by forcing bad pins to be downloaded as a dynamic configuration for your app. For example:

approov device -add h4gubfCFzJu81j/U2BJsdg== -pinMode block

Note that nothing will happen until the next Approov token fetch is made. An existing token may have a lifetime of up to 5 minutes. A new dynamic configuration should then be received. You may be able to see this in the app’s logging. How quickly your app can respond to this update will depend upon the app’s architecture. Once the update has been actioned, you should see an appropriate error from your app when it attempts to make API calls. We suggest you go through this whole process without exiting the app.

You can then simulate what would happen to your running app if a new set of valid pins are transmitted to your app via a dynamic configuration update:

approov device -add h4gubfCFzJu81j/U2BJsdg== -pinMode pin

This sets the pins back to the default for the account. Once any currently fetched Approov token has expired (up to 5 minutes) a dynamic configuration update is transmitted to the app. Depending on the pinning implementation, this might have an immediate impact or after some time if the pins can only be are only rebuilt then. If your app’s pinning implementation cannot rebuild the pins until the app is restarted then it should provide a user message to that effect.

It is vitally important that you test that your app is able to recover from having incorrect pins to correct ones via a dynamic configuration update. This is the process that your app must successfully follow should there be a need to supply new pins to your app over-the-air.

It is also possible to block all app communication, including that between the Approov SDK and the Approov cloud as follows:

approov device -add h4gubfCFzJu81j/U2BJsdg== -pinMode blockAll

In this case you will receive a MITM_DETECTED error from token fetch attempts. This will allow you to check the handling of this in your app.

Continuous Pinning Testing

Pinning relies on the underlying http stack implementation, that is part of the device OS, to implement it. If this underlying implementation is compromised then it is possible that the pinning is not actually restricting TLS connections in the way intended, and potentially allowing an attacker to MITM connections. Approov incorporates various detections of modifications to the runtime environment that may allow such a compromise to occur. In such cases the device will typically not be issued with valid Approov tokens. However, if a particularly lax rejection policy has been selected then there is a danger that such underlying tampering could be occurring whilst valid Approov tokens are issued.

Thus an additional pinning verification mechanism is provided. This allows an arbitrary URL to be specified. The SDK attempts to connect to this the very first time a new app installation tries to fetch an Approov token. The fetch uses the underlying pinning mechanisms of the device OS and specifies a pin that will not be present. Thus the connection attempt should fail. If it succeeds then it indicates that the pinnng mechanism has been compromised in the some way. If this happens then the app installation will never be issued valid Approov tokens.

Set the URL to be used as follows:

$ approov policy -setPinningTestURL https://mydomain.com:443
WARNING: updating the pinning test URL will have an immediate impact on your apps in production. If you wish to continue then please enter YES and return: YES
pinning test URL was updated successfully

The URL should be specified as a full URL with https and may optionally include a port number. This URL should be something that it is possible to perform a successfully http GET operation upon and obtain a 200 OK response. The URL should also not result in a redirect. If the URL is not valid then approov tool will issue a warning. The idea is that if SDK is able to perform this GET, despite the pinning restriction, then this is the trigger to mark the app as being compromised.

We recommend that the URL is one of the key API backend domains that your app uses and is protected using Approov.

You will be able to see devices that have compromised using the pinning-tampered device property flag.

You can see any URL that has been set as follows:

$ approov -getPinningTestURL
https://mydomain.com:443

Finally you can remove the URL at any point using:

$ approov policy -removePinningTestURL
WARNING: updating the pinning test URL will have an immediate impact on your apps in production. If you wish to continue then please enter YES and return: YES
pinning test URL was updated successfully

This feature is only supported with SDKs that are version 2.4.0 or later. Earlier version SDKs will not perform the check.

Security Policies

A security policy is set at the account level and determines which apps may be issued with a valid Approov token.

What is a Security Policy

Approov provides fundamental checks regarding the integrity of the app itself, so that valid Approov tokens are only issued to valid app instances. Additionally, various other runtime integrity checks are also performed and the results transmitted to the Approov cloud server in a secure manner. Whether these checks should result in an invalid Approov token or not is determined by the security policies that are selected. This gives you the flexibility to permit accesses or block them according to your risk assessments and the characteristics of your user base. For instance, if you develop a banking app, you may take the view that no rooted device should receive a valid Approov token. However, other consumer apps, deployed to certain markets or demographics, may require rooted devices to be accepted. Thus the security stance must be informed by the characteristics of the app’s user base and the particular threats that Approov is being used to defend against.

A security policy is shown and specified as three comma separated individual selections as follows:

  • Security Rules: The security rules that should be used. Currently the only valid value is default.
  • Rejection Policy: Policy to be used to determine if a particular request should be rejected and an invalid Approov token issued. This allows preset rejection policies to be set. It is also possible to create custom rejection policies.
  • Annotation Policy: Policy for including flag information in the Approov token itself regarding characteristics of the device or runtime environment that have been determined by the Approov analysis.

When a new account is created it is allocated a security policy of default,default,default. This provides a restricted policy of only issuing valid Approov tokens where no threat has been detected.

Note that security policies may also be set for individual devices as well as the whole account as described in Managing Devices. For this reason blanket policies such as whitelist and blacklist are provided that would not normally be applied to the whole account.

Getting Current Security Policy

It is possible to determine the current security policy for an account using the following command:

$ approov policy -get
security policy is "default,allow-root,all" meaning:
  rules: default (Default security rules)
  rejection: allow-root (Accept rooted Android devices but reject emulators/simulators and Frida/Cydia/Cycript)
  annotation: all (All flags in Approov token)
flag level rejection policy:
  reject app-not-registered       App is not registered, which may indicate that it is fake or tampered
...

This provides information about the security policy selected, including a description of the effect of each component of the policy.

It also outputs a full list of the device property flags that are determined for each device, with a short description for each. This list is subject to dynamic change as new detections are added to Approov. A reject tag is added to the output next to any flag that causes a rejection (the return of an invalid token from an Approov token request). Thus you can see the impact of the chosen rejection policy at a fine grain level.

If you have overridden the preset settings for the individual flag rejection status, then the rejection policy is shown as custom.

Changing Security Policy

The security policy may be changed for the account using the following command:

$ approov policy -set default,allow-root-and-jailbroken,xposed
WARNING: updating the security policy will have an immediate impact on your apps in production. If you wish to continue then please enter YES and return:

This requires an admin role. This particular command will change the security policy to allow jailbroken devices as well and to only show the xposed flag as an annotation. The user must confirm the confirmation prompt in order to apply the new security policy.

If adding the new security policy is confirmed then it will have an effect on the account within 30 seconds. Care must be taken when making changes like this to a live account in case a new policy has a detrimental impact on legitimate users of your app.

Rejection Policies

The rejection policy is the second parameter in the comma separated list for setting a security policy. A number of preset options are available that are used to determine the set of characteristics that are used to reject a particular Approov token request (resulting in an invalid Approov token). It is also possible to have custom rejection policies. The options are as follows:

Policy Description
default Reject all rooted/jailbroken devices, emulators, simulators, frameworks and cloned multiapps.
strict Reject all rooted/jailbroken devices, emulators, simulators, frameworks and cloned multiapps, and strictly require SafetyNet/DeviceCheck if enabled. Note that this causes any devices not capable of running DeviceCheck/SafetyNet to be rejected. Note that if you enable DeviceCheck/SafetyNet with this policy selected then any app that has already launched and fetched an Approov Token prior to that will be rejected. Thus we suggest you only enable this policy some time after setting up DeviceCheck or SafetyNet if you have an existing installed base of running apps.
allow-cloned Reject all rooted/jailbroken devices, emulators, simulators and frameworks. However, cloned apps running in multiapps are allowed.
allow-xposed Allow Android Xposed, but otherwise reject all rooted/jailbroken devices and emulators, simultors, other frameworks and cloned multiapps. This option is provided because for some markets Xposed is a popular modding framework for devices, without an intent to attack a given app. If an Android device is rooted without using Xposed, or if an active Xposed module is implicated in data stealing, then a rejection is made.
allow-root Accept rooted Android devices but reject emulators/simulators, cloned multiapps and Cydia/Cycript/Frida. Detected jailbroken iOS devices are rejected.
allow-root-and-jailbroken Accept rooted Android, iOS jailbroken devices, emulator/simulators, cloned multiapps but reject Cydia/Cycript/Frida.
allow-root-and-jailbroken-only Accept rooted Android and iOS jailbroken devices, but reject emulator/simulators/Cydia/Cycript/Frida/cloned multiapps.
allow-raj-only-short-lifetime Accept rooted Android and iOS jailbroken devices, but reject emulator/simulators/Cydia/Cycript/Frida/cloned multiapps. Moreover the Approov tokens issued have a short lifetime of only 45 seconds (with an additional 15 second grace period).
whitelist A highly permissive policy that generates valid Approov tokens except when there is direct evidence of tampering in the Approov SDK. This generates valid tokens even if the app is not registered. This will typically only ever be applied to individual devices. Note this also has the side effect of disabling any defences that might cause an app to crash if it is being debugged. The app may need to be restarted to remove any already applied protection.
blacklist Always rejects, thus generating invalid Approov tokens. Typically this will only ever be applied to individual devices.

Custom Rejection Policies

In addition to the preset rejection policies, it is also possible to use a customized rejection policy. The most applicable rejection policy should be used as the starting point, then it is possible to add or remove flags that will cause a rejection. If these modifications are made then the rejection policy will be automatically changed to custom. You can set a new security policy at any time, which will discard your custom policy and replace it with the preset policy you select.

Firstly get the current policy to obtain a list of all of the flags, and their current reject status. To add a property to the set that cause a rejection whenever they are detected, you can run a command similar to the following:

$ approov policy -addRejectFlag automated
WARNING: updating the security policy will have an immediate impact on your apps in production. If you wish to continue then please enter YES and return: YES
security policy was set successfully

This causes the flag automated to be added to the set that will cause a rejection. You can see the status by getting the security policy. Note you need an admin role to perform this operation.

You can also remove a property from the rejection set by using a command similar to the following:

$ approov policy -removeRejectFlag automated
WARNING: updating the security policy will have an immediate impact on your apps in production. If you wish to continue then please enter YES and return: YES
security policy was set successfully

Within 30 seconds the customized policy will be applied to new Approov token fetches. Note that, if the app is already running then a new token fetch will be necessary before the new policy is enforced (up to 5 minutes).

It is possible to use any preset rejection policy as the starting point for changes. However, we do not recommend starting with the special policies of whitelist or blacklist as these have other, hidden, attributes.

Annotation Policies

The annotation policy is the third parameter in the comma separated list for setting a security policy. This determines what strings any anno claim in the Approov token may have. These are a subset of the device property flags. This allows some ancilliary information to be present within the token. This is particularly useful where a valid Approov token is still being issued, but analysis has demonstrated some questionable aspects of the requesting device which may need to be analyzed by the backend API in conjunction with other information sources.

The following are valid options:

Policy Description
default No annotations are made.
info This provides the properties risky-device, xposed, automated, automated-launch and non-standard-launch in the annotation. This is useful for putting in place other backend authorization mechanisms to determine if traffic should be allowed depending on the flags present and other factors.
risk This provides the property risky-device in the annotation if the device has a property that makes it high risk. This is useful for putting in place other backend analysis that might limit the operations that risky devices can perform.
all Indicates that all available public properties should be included in the Approov token. This annotation policy should never be enabled for the whole account, only for specific devices, since this information may provide an attacker with significant information about the reasons for any Approov rejection. If constant monitoring of these properties is required in the backend API then we suggest that JWE Approov tokens are used so that the content is encrypted. Note that an alternative mechansim is provided using Attestation Response Codes and we recommend that this is used instead unless the results of the property checks are to be used as part of the request processing.

Key IDs

It is possible to associate a key ID with all JWS tokens created by Approov. You may arbitrarily choose the key ID as follows:

$ approov secret -setKeyID mykeyid

Once this is set then all issued JWS tokens will contain a kid field in the header with the value provided. The currently set value can be obtained with:

$ approov secret -getKeyID

Inclusion of a key ID can be removed with:

$ approov secret -clearKeyID

The addition of a key ID does not impact tokens issued for certain Approov managed domains, such as shapes.approov.io nor for domains using encrypted JWE tokens.

Managing Devices

Approov provides facilities to apply specific policies to particular devices that are being used. This affords flexibility in work practices during development, in continuous build systems, and to allow pentesting and analysis of an Approov protected app.

Extracting the Device ID

In order to modify the policy of a particular device, its ID must be extracted. There are several methods by which this extraction may be done.

  1. Via the logging that is output by Approov when the SDK is first initialized. On Android this can be seen by looking in logcat under the Approov tag. For instance, the following is logged when starting a demo app. The base64 string h4gubfCFzJu81j/U2BJsdg== at the end of the line is the device ID. It represents a 128-bit ID for the app and device combination. On iOS this logging is available in the documents folder for the app in the file Approov.log.

    2019-05-20 13:56:57.789 29546-29546/com.criticalblue.demo I/Approov: test-account, com.criticalblue.demo, 2.0.4(1021), h4gubfCFzJu81j/U2BJsdg==
  2. Via extraction from an Approov token that has been generated on the device. A loggable token contains the device ID directly in the did claim. It can be extracted from an ordinary Approov token using the command line tool, for example:

    $ approov token -check eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkaWQiO…
    failed: {"did":"h4gubfCFzJu81j/U2BJsdg==","exp":1558626254,"ip":"85.233.105.183"}
  3. By calling the getDeviceID() method on the SDK interface. This provides the base64 encoded string of the device which may be presented in some way within the app.

  4. By looking at the devices that have recently requested an Approov token using approov device -getFetches timed. Note that if you are adding a custom device you can use the shorthand approov device -add latest to select any device that has made a request in the last two minutes, as long as it is the only device that has done so.

Device ID Stability

To respect an individual’s right to privacy, both Apple and Google limit the ability to uniquely identify a device. The identifiers that are truly fixed for a device are hidden and device IDs are generated on-the-fly for new app installations. These, on-the-fly, platform generated device IDs are consistent for the same app but vary across iOS and Android as described below.

Approov device IDs are partly derived from the platform provided device ID, but also include information derived from the app identifier, so device IDs are always per-app device IDs. Thus if you are developing two different apps on the same device you will find that they will be allocated different device IDs. Moreover, any change to the package name of the app will also change the device ID.

Thus you must be aware that the ID for a particular device may change, and this will cause the applied policy for that physical device to be lost. The new device ID must be extracted and the device added again, with the old redundant one removed.

The underlying identifiers used to derive the Approov device ID are as follows:

  • iOS: The identifierForVendor is used. This ID remains constant per app vendor as long as there is one or more apps from the vendor installed. If all the apps are uninstalled then a new ID will be allocated. All apps from the same vendor share the same ID. Thus a good strategy is to always have another app signed by the same developer installed on the device to anchor the device ID for all of them.
  • Android: The ANDROID_ID is used. Since Android O, this is unique to an app installation and registered device user and is stable across app uninstalls and reinstalls. It will change if your app signing key changes or if the device user performs a factory reset.

Adding a Device Security Policy

An individual device may be assigned a specific security policy as follows:

approov device -add h4gubfCFzJu81j/U2BJsdg== -policy default,whitelist,all

This causes the given device to have the particular policy applied without applying it to the rest of the account. This change should be actioned for new Approov token requests within 30 seconds. Remember though that if your app is already running on the device and has fetched a token then it might not need to fetch a new one for up to 5 minutes, in which case the revised policy will only be apparent when that new fetch occurs.

The example rejection policy of whitelist is a common one for development. By whitelisting the device, it is possible to always get a valid Approov token to access endpoints without needing to re-register modified apps. This policy also provides valid Approov tokens when debugging the app.

If the device is the only one that has been used recently on your account you can use the latest shortcut, rather than having to specify the device ID explicitly.

approov device -add latest -policy default,whitelist,all

Although, you should note that, the device must have fetched an Approov token in the last two minutes, and must be the only device doing so in that time. This option cannot be used reliably once you have your app in production where there may be a large number of end user Approov token fetches in the 2 minute period.

There is a maximum of 25 devices that may be added to an account at one time.

Labelling a Device

When adding a device it is also possible to set a label for it to make it easier to remember what device it is:

approov device -add h4gubfCFzJu81j/U2BJsdg== -policy default,blacklist,default -label bobs-iPhone7

This label will then be shown when you list the devices. Note that if you wish to include spaces in the label then you must surround it with quotes. This example uses the rejection policy blacklist to ensure the device never receives a valid Approov token. This may be useful for testing.

Setting Pinning Mode

It is also possible to set the pinning mode for a particular device. This changes the way pins are handled for the device and can cause a new dynamic configuration to be downloaded to the app. These options are covered in more detail in Testing the Pinning Implementation. This command removes all pinning for the app, by causing an empty set of pins to be transmitted as the dynamic configuration:

approov device -add h4gubfCFzJu81j/U2BJsdg== -pinMode unpin

This has the further impact of sending a special dynamic configuration update to the app on the particular device that has all the certificate public key pins removed. This causes all pinning protection to be removed from the app, allowing a proxy (such as Charles Proxy or MITM Proxy) to be used to intercept traffic between the app and the API endpoints. This can be useful for debug or pentesting. Note that some apps may require a relaunch to unpin after receiving the update if they are not written to be immediately reactive to pinning changes.

Other options may be provided for the pinning mode as follows:

  • block: This transmits an fixed but invalid pin for in the dynamic configuration for all domains that have had pins added. This will force the app to experience a pinning failure in the same way it would if the API endpoint’s certificates had changed. This can be used for testing what happens in the app when such a certificate mismatch occurs.
  • blockAll: This works like block but it also causes the Approov channel to detect a MITM. THis simulates what happens if all TLS traffic is being intercepted. In this case any Approov token fetch (that needs to fetch a new token) will receive a MITM_DETECTED error.
  • pin: This is the default and returns the device to the default pinning for the account.

Note that since no security policy is explicitly set, the device is assigned the current security policy for the account. You may also set an explicit security policy for the device in the same command.

Listing Your Devices

A full list of devices that have had a special override security status can be obtained with:

approov device -list

This produces a list, for example:

1 device:
 h4gubfCFzJu81j/U2BJsdg== default,whitelist,all  unpin  A N Other

It shows the device ID, the security policy currently being applied and any pinning mode that has been set (or pin by default).

The name of the user that added the device is also provided. If a device label has been set then this is also shown. This makes it easier to determine the user of a particular device.

Removing Devices

A particular device can be removed as follows:

approov device -remove h4gubfCFzJu81j/U2BJsdg==

The standard account policy will be applied to the device within 30 seconds for new Approov token fetches. Note that, if the app is already running then a new token fetch will be necessary before the new policy is enforced (up to 5 minutes).

Device removal is not restricted to the user that added the device.

Removing Multiple Devices

Sometimes it is desirable to be able to remove multiple devices with a single command. For instance, if we have:

approov device -list
3 devices:
 h4gubfCFzJu81j/U2BJsdg== default,whitelist,all  unpin  A N Other
 VI2c+UugQ6L7v0wkovXOSg== default,whitelist,all  pin  A N Other
 iDpOemiTdame9qvAQF4w/g== default,whitelist,all  pin  Me

You can issue a command to remove all devices associated with the user name A N Other as follows:

approov device -removeMatching "A N Other"
2 matched devices:
 h4gubfCFzJu81j/U2BJsdg== default,whitelist,all  unpin  A N Other
 VI2c+UugQ6L7v0wkovXOSg== default,whitelist,all  pin  A N Other
WARNING: are you sure you wish to remove these devices. If you wish to continue then please enter YES and return: YES
removed h4gubfCFzJu81j/U2BJsdg==
removed VI2c+UugQ6L7v0wkovXOSg==

You must specify the name in quotes if it contains any spaces. The matching devices will be listed and you will be asked for confirmation.

Note that the provided string also matches against any label that has been provided.

Banning a Device

This facility allows any individual device to be banned on the basis of its device ID. You would typically do this as a result of malicious activity that you may have detected. Such a device will then be unable to receive valid Approov tokens.

The first step is to determine the device ID by obtaining an Approov token that has been issued to that device. Each Approov token contains a did claim which holds the device ID. You can extract the claims from the token using the Checking Token Validity command. So, assuming a device ID of h4gubfCFzJu81j/U2BJsdg== was extracted, the device can then be banned with the following command:

$ approov device -add h4gubfCFzJu81j/U2BJsdg== -banMode ban
successfully set device h4gubfCFzJu81j/U2BJsdg==

The next time this device tries to fetch an Approov token it will be added to the banned list and will not receive a valid Approov token.

If you have the all Annotation Policy selected then tokens rejected due ban have did-ban listed as a rejection reason.

Once the ban has been actioned there is no need to retain the device in the custom set for Approov, so you can remove it again with:

$ approov device -remove h4gubfCFzJu81j/U2BJsdg==
successfully removed device h4gubfCFzJu81j/U2BJsdg==

The ban is only related to the particular device ID. On iOS in particular, if the app containing the Approov SDK is uninstalled and reinstalled again it may be allocated a different device ID and thus evade the ban. In order to combat this the DeviceCheck Integration can be used to provide a permanent ban of a physical device, unrelated to the device ID being used.

Removing a Device Ban

A device ban can be removed if the current device ID can be obtained. As discussed in Banning a Device, this may be obtained from an example Approov token issued to the device. Initiate the unban as follows:

$ approov device -add h4gubfCFzJu81j/U2BJsdg== -banMode unban
successfully set device h4gubfCFzJu81j/U2BJsdg==

The next time this device tries to fetch an Approov token it’s ban status will be removed, and it will be issued with a valid Approov token (presuming it meets all of the other criteria). Once the unban is actioned, remove the device from the custom device set.

Once a given device ID has been unbanned, it cannot be banned again (unless all device state is cleared).

Getting State of a Device

You can obtain a list of the persisted flags associated with a particular device ID as follows:

$ approov device -getDeviceState h4gubfCFzJu81j/U2BJsdg==
did-ban

A list of flags associated with the device ID is provided. In this case it shows that this particular device has been banned. You may see other flags associated with persisted state, especially those related to DeviceCheck and SafetyNet. The evaluation of these tokens are held as persisted state so that the costly exercise of obtaining these tokens doesn’t have to be repeated each time the app on a particular device is launched.

If the device has not been used on the Approov account then you will see the message device state has not been set.

If a device ID has been banned, and then subsequently unbanned, you will see both did-ban and did-unban in the list. The did-unban always takes priority.

Clearing All Device State

It is possible to clear the persisted state of all devices in the account. This means that any previously banned devices will become usable again. Moreover, if you are using DeviceCheck Integration or SafetyNet Integration then the previous results of these token fetches will be erased and devices will be forced to perform the checks again next time they connect to the Approov service.

You can clear the state as follows:

$ approov device -clearDeviceState
WARNING: clearing device state will require all app installs to redo any DeviceCheck/SafetyNet checks (consider SafetyNet API quota limits)
WARNING: it is not advised to use this option if DeviceCheck autoban (bit availability of both) is being used
WARNING: this will have an immediate impact on your apps in production. If you wish to continue then please enter YES and return: YES
successfully cleared all device state

You need an admin role to perform this operation and pay careful attention to the warnings. In particular, if you are using SafetyNet and you clear the device state, this means that new SafetyNet attestations will be required for all devices as they preform their first Approov token fetch after the reset and this may exceed the SaftyNet API quota you have in place.

Note that clearing the device state will have no impact on your billing or the calculation of hourly, daily or monthly active devices. However, it will impact the derivation of the new-did flag so existing app installations will be considered to be new the next time they fetch an Approov token.

If you use this in combination with Automatic Device Banning then the count of installations on the device will be incremented. This could cause unexpected device banning.

Device Filters

This section covers the optional device filtering feature in Approov.

Filtering Purpose

Facilities are provided to obtain detailed information about the attributes of devices. Filters may then be defined and checked against all devices attempting to fetch Approov tokens. These filters can match against specific device attributes.

When a filter matches then this is shown in a special graph within the Live Metrics. This allows an appreciation of the timing and prevalence of particular attributes to be known. This can be useful for understanding the population of devices that are using your Approov account. Moreover, these facilities may be used for understanding any suspicious behaviour and/or by CriticalBlue support staff understanding any irregularities in the operation of apps using your account.

Options are provided to ban particular devices with specific characteristics, and even to apply special security policies to matching devices. This may be used by CriticalBlue support staff to run customized security rules that are able to gather more detailed telemetry from specific devices for analysis.

Getting Specific Device Information

It is possible to obtain more detailed device information for any device that has add a device specific security policy added. At least one Approov token fetch must be performed to collect the information (remembering that a previously fetched Approov token may take up to 5 minutes to expire before the app needs to fetch a new one, if it is not restared).

Once this is done the information can be obtained as follows, by specifying the device ID:

$ approov device -getInfo qZka0yfv+ExvOq3PRh6pGw==
captured: 2020-07-23 11:51:26 BST
rejection-flags: app-not-registered
public-flags: app-not-registered,rooted,root-risk,xposed,init-config-outdated
ip: 1.2.3.4
device-id: qZka0yfv+ExvOq3PRh6pGw==
device: Android 8.1.0, Nexus 5X, google, bullhead, en
archid: arm64-v8a
device-props: {'Model':'Nexus 5X','Fingerprint':'google/bullhead/bullhead:8.1.0/OPM6.171019.030.E1/4805388:user/release-keys'}
sdkid: 4000
sdk-version: 2.4.0
app-name: Approov OkHttp Shapes
app-version: 3.0(3)
appid: com.criticalblue.demo
app-id-sig: NhVaAEGs3U6fLObhZAIdRh71wVF7kSOL0aAMv+e5TvU=
app-sig: tL8CNNpf4XlekWkwuyJaCRtcntJyjZ1ujYJ7CZMO+Fk=
attest-reason: launch

The information most recently collected is shown, along with the local time of its capture. The information consists of a series of <key>:<value> attributes. The exact set of information may vary over time and also between iOS and Android.

In this case the public-flags shows the full set of device property flags that have been collected. The IP address of the client is always shown too, independently of the IP Tracking Policy that has been selected. Although, you should note that, the IP addresses are only held in the memory of the Approov cloud servers and never committed to any file storage.

In the case of Android the device-props provides more detailed information about the particular model and OS build of a device (although it does not uniquely identify an individual device). The app-sig is always present and shows the signature of the particular app. On Android the app-id-sig is also present and provides the overall identity signature used when registering an App Bundle (as the raw app signature may change depending on the app delivered to an individual device).

The individual device information is collected and held by the Approov servers on a best effort basis. The information may be cleared from time to time so you should save it in a local file if you wish to keep it more permanently.

Analyzing New Devices

Information for new devices (i.e. device IDs that have not be seen previously) is collected automatically. It can be obtained by using new-did as the parameter for -getInfo:

$ approov device -getInfo new-did
--- w4mmGFZkpz5oPz6w6gl1Cw== 2020-07-23 12:10:43 BST ---
rejection-flags: app-not-registered
public-flags: app-not-registered,jailbroken,init-config-outdated,devicecheck-unavailable
ip: 1.2.3.4
device-id: w4mmGFZkpz5oPz6w6gl1Cw==
device: iOS, 12.1.2, iPhone7,2, en_ES
archid: arm64
sdkid: 4505
sdk-version: 2.4.0
app-name: Approov Shapes
app-version: 1.0
appid: ios.swift.shapes.demo.approov.io
app-sig: DRJNqt37tsdHwb9FKFT80dPqXlOHqZnZy68zAiVSsvM=
attest-reason: expiry

A stream of information for the the most recent new devices is provided, with a separator providing the ID and the local capture time.

The new device information is collected and held by the Approov servers on a best effort basis. Only the information for the last 100 new devices is held and earlier entries are discarded. Note also that the information may be cleared from time to time so you should save it in a local file if you wish to keep it more permanently.

If you wish to obtain information for all new device IDs then the following short bash script can be used. This appends to the approov-new-did.txt file any new devices on a per-minute basis. This ensures that, unless there are more than 100 new devices per minutes, all the new device information will be captured.

#!/bin/bash

while true; do
  echo "getting new devices"
  approov device -getInfo new-did -clear >> approov-new-did.txt
  sleep 1m
done

The use of the -clear option ensures that prior data is cleared on each call so there is no duplicate information in the generated file. Note that this approach cannot be used by more than one user at a time.

Adding a Device Filter

A device filter may created that checks the attributes of every device fetching an Approov token to determine if it has a particular attribute. For instance:

$ approov filter -add myip -key ip -matchValue 1.2.3.4
successfully set filter myip

This adds a new filter called myip. This name is used to reference the filter and also appears in live metrics if the filter is matched. The name is restricted to a maximum of 20 characters of lower case alphanumerics and the - sign only. If a filter name is reused then the previous settings are overridden.

The -key option determines the particular key in the information to be checked against, ip in this case. If the key is not present then the match never occurs. The -matchValue specifies the specific text for the value for the match to occur. In this case the match is for any device using the IP address 1.2.3.4. (This initial form requires an exact verbatim match, to have a single filter with more general matching semantics, see the section on Regular Expression Filtering.)

With the default options the only impact is to show the match in the live metrics.

Filtering may be restricted to only new devices by using the -newDIDOnly flag:

$ approov filter -add special-app-sig -key app-sig -matchValue DRJNqt37tsdHwb9FKFT80dPqXlOHqZnZy68zAiVSsvM= -newDIDOnly
successfully set filter special-app-sig

In this case the matching is looking for a particular app signature for device IDs being used for the first time.

A maximum of 25 filters may be defined at any one time.

Analyzing Filtered Devices

It is possible to capture full device information for any device that matches a filter. To enable this you must use the -captureDeviceInfo flag on the added filter, for example:

$ approov filter -add myip -key ip -matchValue 1.2.3.4 -captureDeviceInfo
successfully set filter myip

Information for any device that matches the myip filter is then collected. The informaiton can be obtained by using filtered as the parameter for -getInfo:

$ approov device -getInfo filtered
--- w4mmGFZkpz5oPz6w6gl1Cw== 2020-07-23 12:10:43 BST ---
matched-filters: myip
flags-all: app-not-registered,jailbroken,init-config-outdated,devicecheck-unavailable
ip: 1.2.3.4
device-id: w4mmGFZkpz5oPz6w6gl1Cw==
device: iOS, 12.1.2, iPhone7,2, en_ES
archid: arm64
sdkid: 4505
sdk-version: 2.4.0
app-name: Approov Shapes
app-version: 1.0
appid: ios.swift.shapes.demo.approov.io
app-sig: DRJNqt37tsdHwb9FKFT80dPqXlOHqZnZy68zAiVSsvM=
attest-reason: expiry

A stream of information for the the most recent filter matches is provided, with a separator providing the ID and the local capture time. Note also that the first property shown is matched-filters which lists all of the filters that were matched by the device.

The device filtering information is collected and held by the Approov servers on a best effort basis. Only the information for the last 100 new devices is held and earlier entries are discarded. Note also that the information may be cleared from time to time so you should save it in a local file if you wish to keep it more permanently.

If you wish to obtain information for all filtered devices then the following short bash script can be used. This appends to the approov-filtered.txt file any filtered devices on a per-minute basis. This ensures that, unless there are more than 100 filtered devices per minutes, all the information will be captured.

#!/bin/bash

while true; do
  echo "getting filtered devices"
  approov device -getInfo filtered -clear >> approov-filtered.txt
  sleep 1m
done

The use of the -clear option ensures that prior data is cleared on each call so there is no duplicated information.

Regular Expression Filtering

Normally when a filter -matchValue is specified it must be an exact verbatim match for the specified key’s value. However, it is also possible to do Regular expression matching if the -regex option is used. For example:

$ approov filter -add android7 -key device -matchValue "Android 7" -regex
successfully set filter android7

This creates a filter that checks for the substring Android 7 in the device property. By default a specified regular expression performs a substring match. However, the full power of regular expressions may be used. There is a useful interactive tool here for constructing regular expressions.

Regular expression filtering can be particularly useful for checking if a device has particular properties in the flags-all device information key. Simply specify the required flag name with -regex and this will do a substring match to check if the flag is set, regardless of other flags (being careful to make sure the flag name is not itself a substring of some other flag name).

Conjunction Filters

It is possible to create a filter that is only matched if a set of other filters all match. This allows the creation of more complex conditions that require matches across multiple different device information keys.

For instance, if you have previously setup a filter called android7 and another one called myip, then you create a new filter that is the conjunction of these two as follows:

$ approov filter -add both-matched -conjunction android7+myip
successfully set filter both-matched

This new filter will only match is both the input filters are matched on the same device. You specify the set of input filters using a + separated list provided to the command. Note that these inputs must be ordinary filters and not conjunction filters themselves.

When you first add a conjunction filter a check is made that the input filters are present. However, if these are subsequently removed then the conjunction filter will never match since all inputs must be present for a match to occur.

User Properties

It is possible to set a user property on the Approov SDK. This user property is simply a string (of up to 128 characters) that is passed to the Approov cloud on all subsequent times that the device fetches an Approov token. It can be set as follows, presuming the value is available in property:


Approov.setUserProperty(property);

Approov.setUserProperty(property);

This value will then appear with the key user-property in the collected device information. Thus it is possible to create a device filter that matches certain values (or more complex patterns using the regex feature. Thus this can be used to highlight devices with particular properties, or even to ban them or mark them as being risky.

The string should be composed of printable ASCII characters only. Any other characters are mapped to ?, including double quotes (") and forward slashes (/).

User properties are only supported in version 2.5.0 and later SDKs.

Listing Device Filters

All currently set filters can be shown as follows:

$ approov filter -list
2 filters:
 myip             ip: 1.2.3.4
 special-app-sig  app-sig: DRJNqt37tsdHwb9FKFT80dPqXlOHqZnZy68zAiVSsvM=  newDIDOnly

The list of options associated with the filter are shown on the right hand side of the filter listing.

Removing a Device Filter

Any named filter can be removed as follows:

$ approov filter -remove special-app-sig
successfully removed filter special-app-sig

If you remove a filter that is an input to a conjunction filter, then it will never match until the input filter is replaced,

Rejecting Filtered Devices

A -reject option is provided so that any device which matches is automatically rejected, and will not receive a valid Approov token. For example:

$ approov filter -add myip -key ip -matchValue 1.2.3.4 -reject
WARNING: using the ban or reject option will have an immediate impact on your apps in production. If you wish to continue then please enter YES and return: YES
successfully set filter myip

This rejects any device that attempts to fetch an Approov token from the IP address 1.2.3.4.

You should be especially careful when using this option as it is available with dev role priveleges. If a match is used that covers too many devices then this could cause large numbers of app users to be rejected. Always test the match without reject first and examine the metrics to determine the prevalence of the match.

Banning Filtered Devices

A -ban option is provided so that any device which matches is automatically banned. This sets the did-ban flag on the device and it will not ever receive valid Approov tokens. For example:

$ approov filter -add myip -key ip -matchValue 1.2.3.4 -ban
WARNING: using the ban or reject option will have an immediate impact on your apps in production. If you wish to continue then please enter YES and return: YES
successfully set filter myip

This bans any device ID that attempts to fetch an Approov token from the IP address 1.2.3.4.

Note that any such ban will be permanently associated with the device ID, and the device ID will continue to be banned even if the filter is subsequently removed.

You should be especially careful when using this option as it is available with dev role privileges. If a match is used that covers too many devices then this could cause large numbers of app users to be rejected. Always test the match without banning first and examine the metrics to determine the prevalence of the match.

In an emergency it is possible to clear all of the did-ban states using the Clearing All Device State option. This requires an admin role. This clears all device state and thus undoes any prior device ID bans

Marking Filtered Devices as Risky

A -risky option is provided so that matching devices are automatically marked as risky, for example:

$ approov filter -add myip -key ip -matchValue 1.2.3.4 -risky
successfully set filter myip

This means any request from IP address 1.2.3.4 will have the risky-device flag asserted.

The impact of this is two-fold:

  • The device will be issued Approov tokens that have a 2 -minute lifetime rather than the usual 5.
  • If the risk Annotation Policy is set then this means that the risky-device flag will be set. This enables backend systems to observe this annotation and potentially perform different actions for the device.

Custom Filtered Security Policy

It is possible to use the special device ID value ++FilteredSecPolicy++w== to provide a security policy that is applied to any device which matches specific filters. Firstly add this pseudo device ID as follows:

$ approov device -add ++FilteredSecPolicy++w== -policy alt-rules,default,default
successfully set device ++FilteredSecPolicy++w==

For the filtered policy to have an effect, you should not use the same security rules setting as the default for your account. The example alt-rules shown above will not work (there are no such rules). Normally this feature is used in conjunction with Approov support staff for more detailed analysis of specific activity on your account and so you should really contact Approov support if you wish to use this feature.

You are not able to use the -pinMode or -banMode options on this special device ID. However, the -probeURL value is applied.

In order to enable this behaviour for a particular filter you must use the -execFilteredSecPolicy option, for example.

$ approov filter -add myip -key ip -matchValue 1.2.3.4 -execFilteredSecPolicy
successfully set filter myip

This causes any request from IP address 1.2.3.4 to execute the custom filtered security policy.

It is also possible to make a certain percentage of all devices execute the special filtered security policy, instead of the standard one for the account. You can simply set the percentage as follows:

$ approov filter -setSamplingPercentage 0.1
successfully set sampling percentage

This sets the sampling percentage to 0.1%. An admin role is required to make this change. This means that 0.1% of all devices will execute the special filtered secuity policy rather than the standard account security policy. This determination is made on the basis of the device ID so that the same device will either be subject to the special policy or not. However, the selections change on each day so the sampling moves across the device population.

You can always see the current setting with:

$ approov filter -getSamplingPercentage
sampling percentage is 0.10%

Adding this special security policy causes a very small addition to the latency of Approov token fetches, independently of the number of devices that use it. Thus we suggest you only leave this special policy added for as long as you need to use it.

Observing All Token Fetch Devices

A record is kept of the device IDs of any apps that are fetching Approov tokens. This is held in time order, with an optional timestamp. It can be obtained with:

$ approov device -getFetches timed
qZka0yfv+ExvOq3PRh6pGw== 2020-07-23 12:10:45 BST
qZka0yfv+ExvOq3PRh6pGw== 2020-07-23 16:27:12 BST
w4mmGFZkpz5oPz6w6gl1Cw== 2020-07-23 16:27:20 BST

This is useful for analysis of the device IDs that are using the account, and perhaps frequency of use analysis to determine if particular device IDs are responsible for a high use of the account. These devices can then be added as custom devices for more detailed analysis if required. The parameter timed indicates that timestamps should be included.

The token fetch device ID information is collected and held by the Approov servers on a best effort basis. Only the information for the last 1000 requests is held and earlier entries are discarded. Note also that the information may be cleared from time to time so you should save it in a local file if you wish to keep it more permanently.

A simple script such as the following can be used to collect this information into the local file approov-fetches.txt:

#!/bin/bash

while true; do
  echo "getting latest fetches"
  approov device -getFetches untimed -clear >> approov-fetches.txt
  sleep 1m
done

This simply captures the latest untimed information every minute and uses the -clear option to discard the obtained information so that it is not duplicated in the resultant file.

Analyzing Captured Streams

Information collected regarding fetches or the attributes of particular devices can be easily manipulated using standard commands. For instance, imagine we have captured approov-fetches.txt showing two different devices using the account as follows:

qZka0yfv+ExvOq3PRh6pGw==
w4mmGFZkpz5oPz6w6gl1Cw==
w4mmGFZkpz5oPz6w6gl1Cw==
w4mmGFZkpz5oPz6w6gl1Cw==
w4mmGFZkpz5oPz6w6gl1Cw==
qZka0yfv+ExvOq3PRh6pGw==
qZka0yfv+ExvOq3PRh6pGw==
w4mmGFZkpz5oPz6w6gl1Cw==
w4mmGFZkpz5oPz6w6gl1Cw==

We can easily count the number of occurrences of each device ID as follows:

$ sort approov-fetches.txt | uniq -c
      3 qZka0yfv+ExvOq3PRh6pGw==
      6 w4mmGFZkpz5oPz6w6gl1Cw==

We can use this technique to anayze the frequency of use by certain device IDs or the frequency of occurrence of particular device attributes. This method can be used to identify commonly occurring device attributes, which can then be used in further searches in the original file to find the full context of each interesting match.

Note that this output can of course itself be piped to a file, such as output.txt. You can then show the most commonly occurring repeats as follows:

$ sort -h -r output.txt | less

The -h and -r options cause the most frequently occurring lines to be shown first.

Token Binding

This section covers the optional token binding feature in Approov.

If you are able to use one of our Quickstart Frontend Integrations then these typically include support for token binding, by specifying a particular http header that holds the source data for the hash. Similiarly, the Quickstart Backend Integrations are able to extract the same information from the header and verify that the correct token binding is included in the Approov token.

Token Binding Concept

Token binding extends the security of the Approov token through a strength in depth approach. The mechanism ties an arbitrary string to an Approov token by including its hash in one of the claims. The facility is intended for long lived data, such as an OAuth token or a user session identifier, that can be used to uniquely identify a user. The data is supplied to the Approov SDK as an ASCII encoded string. The SDK takes the string and calculates its SHA256 hash. This is then provided inside the Approov token in the pay claim as a base64 encoded string.

If the binding data changes then this invalidates any currently cached Approov token and a new one is requested on the next token fetch. Thus it is important not to use rapidly changing data for binding. Ideally long lived user session tokens should be used that will likely not change during normal app usage.

Note that the hashing of the data sent in the pay claim is always done in the SDK itself. Only the SHA256 hash of the data is sent to the Approov cloud service, so there is no need to be concerned about additional Personal Identifiable Information (PII) being sent to the Approov cloud service.

Setting the Binding

The data value may be set with the following method, where data is a string representing the data to be bound:


Approov.setDataHashInToken(data);

Approov.setDataHashInToken(data);

This checks the SHA256 hash calculated for data value against any current value that is held. If the value is different, then any cached Approov token is cleared. Any subsequent Approov token fetch call will obtain a new Approov token. The maximum rate at which new tokens can be fetched may be rate limited to prevent excessive usage if the binding data is modified and a token fetched in a tight loop.

The data binding is held in the pay claim of the generated Approov token. The same value is retained in all subsequently generated Approov tokens until it is changed with another setDataHashInToken call.

Note that once a pay claim has been added it is not possible to remove its inclusion in the running app, only change its value.

Generating Example Token with Binding

The example token generation also supports the ability to generate a token with a pay claim. This can be used to test backend integrations that must perform the same hashing calculation to compare the claim. For example we can use:

$ approov token -genExample your.api.com -setDataHashInToken custom-data
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJl…

You can decode the generated Approov token string as follows:

$ approov token -check eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJl…
valid: JWS {"did":"ExampleApproovTokenDID==","exp":1558640470,"ip":"1.2.3.4","pay":"tih+xRFV8PMsDhKthuFdvqWtQpKdT+K8X5W3258EJnU="}

This shows the pay claim hash derived from the string custom-data:

{
  "did": "ExampleApproovTokenDID==",
  "exp": 1558640470,
  "ip": "1.2.3.4",
  "pay": "tih+xRFV8PMsDhKthuFdvqWtQpKdT+K8X5W3258EJnU="
}

Backend Integration Impact

If the token binding features are used then the pay claim must be checked on the backend to ensure the hash is consistent with the source data being presented. This data must be present in some other part of the request so that it can be extracted for comparison with the hash in the Approov token.

The recommended process for checking the pay claim against the data provided in the request is as follows:

  1. Do a basic check of the Approov Token to see if it is valid.
  2. Check whether the token has a pay claim. If claim is not present then the token may be from the Failover service.
  3. If the claim is present then the data should be compared with the SHA256 hash of the data you provided to Approov. In some cases, such as when you are providing an OAuth token and you have yet to retrieve this in the application code, you should use a known none value which you both pass into the token fetch call in your app and in your server side payload check. This is because your backend code must cope with Failover tokens. Thus you must ensure normal tokens always have some content in the pay claim or else the logic for handling failover tokens (which will only ever be issued in the unlikely case of an Approov primary outage) could provide a back door for avoiding a matching pay claim.

Apple DeviceCheck Integration

This section covers the integration between Approov and Apple’s DeviceCheck feature. If this integration is used then the Approov SDK forces the iOS device to generate a token that is passed to the Approov servers. This can then be checked with Apple and proves that the token was generated on a real iOS hardware device. This provides an additional level of protection against any spoofing attempts.

This feature is particularly useful if there is suspicion of malicious or fraudulent activity occurring via the continual re-installation of an app on the same physical device. The app itself may be unmodified and running in a clean environment so would receive a valid Approov token. The integration allows a specific physical iOS device to be banned once fraudulent activity has been detected on it so it is not able to receive valid Approov tokens again.

If this option is used then the iOS Approov SDK must make a call to generate a token to identify the device. This needs to be done on the first Approov token fetch after launching the app. Performing this operation requires additional network connection(s) and CPU processing time, over which the Approov SDK has no control. This can substantially delay the fetch operation on the iOS platform by adding up to 2500 ms of additional latency.

DeviceCheck Concept

As discussed in Device ID Stability, the device ID reported on iOS automatically changes if an app is removed and then reinstalled. This is to preserve the privacy of the end user, as otherwise it would be possible to track an individual indefinitely via the device ID reported on their device. However, the inability to track specific devices creates some challenges with blocking specific malicious or fraudulent behaviour emanating from a particular device. If blocking is based on a device ID then the malicious actor can always circumvent any banning via reinstallation of an app. IP based blocking can also be evaded by the use of proxies.

Apple have recognized this as an issue and have introduced the DeviceCheck feature to provide some very limited tracking of specific physical devices that maintains user privacy. The facility allows up to two bits to be recorded for each physical device for each Apple developer account. These bits can be used to record information such as the detection of some fraudulent behaviour on the device.

Obtaining the bit status values and updates to them is performed by calling an Apple server API. In order to identify the device to this API it is necessary to obtain a Device Token. This is an ephemeral token (approximately 3KB in size) that identifies the device. Of course to prevent this itself being used to identify the device, and breaking the privacy policy, it is derived from a randomly generated nonce value so is different every time even on the same device. Since accessing the Apple API requires an authorization key this cannot be done in the app itself, since if this key was extracted it could be used to make arbitrary bit changes for other devices. Thus the API calls must be performed server side, necessitating that a protocol be established to communicate the DeviceCheck token from the mobile app to the server.

The Approov integration of DeviceCheck handles all of this integration complexity. If a DeviceCheck key is added to the Approov account, then the Approov SDK automatically collects and transmits the DeviceCheck tokens to the Approov servers. This token is then used to get and update the status of the device physical bits and prevent banned devices from being issued with valid Approov tokens. The simple check of the validity of the token also ensures that the traffic is emanating from a real iOS hardware device. Commands are provided to easily ban and and unban devices, and an optional automatic banning facility is available to automatically detect and ban devices associated with repeated app uninstalls and reinstalls.

The status of the DeviceCheck will be reflected in the device property flags:

  • devicecheck-unavailable: Indicates the the DeviceCheck capability is not available on the device.
  • devicecheck-complated: DeviceCheck has been completed on a device.
  • devicecheck-failed: DeviceCheck has failed indicating that the provided device token was not valid.
  • devicecheck-ban: Indicates a permanent device ban associated with the physical device.

Setting the DeviceCheck Key

In order to use the Approov DeviceCheck integration you need to add an Apple authentication key to your Approov account. This key only needs permissions to access and update the two bits provided for physical device. This is used by the Approov servers to dynamically query the Apple servers when new devices are added, and to update the settings of the bits if a particular device is being banned (or subsequently unbanned).

Log into your Apple Developer Account, click on Account on the top menus, login and then navigate to the “Certificates, IDs & Profiles page”. Here you will see the list of keys and certificates that have been issued for your account, such as this below.

Apple Certificates Page

Select the “Keys” menu on the left hand side to navigate to the keys that have been issued for the account.

Apple Keys Page

You need to click on the blue plus button to add a new key. Type in the name of that you want to call the key (you an choose anything that is meaningful to you) and click the option for DeviceCheck.

Register New Key

You then press the “Continue” button and a dialog will be shown asking you to confirm the key addition.

New Key Confirmation

Click Register. You will then be provided with a dialog that gives you an option to download the private key that has been generated. Click this button. You will only get once chance to download this key so make sure the file is saved somewhere that is accessible for the next steps.

New Key Download

When the key is downloaded you will get a dialog such as the below with details of the key. The .p8 file itself should have been written to the Downloads folder that your browser uses by default. Also make a note of the Team ID value shown on the top right of the screen next to your company name. You will also need that.

Downloaded Key

Now that you have a private key you need to make it accessible to Approov using the approov command line tool.

$ approov devicecheck -addAuthKey AuthKey_XXXXXXXXXX.p8 -teamID YYYYYYYYY -bits bit0
WARNING: this will have an immediate impact on your apps in production. If you wish to continue then please enter YES and return: YES
device check information added

Where AuthKey_XXXXXXXXXX.p8 is the private key file you downloaded and YYYYYYYYY is your team ID. In this case bit0 is selected so that the Approov service can read and update bit 0 of the two bits available per physical iOS device. You can change this to bit1 if you would rather use that bit instead. Note that if you do not specify -bits then it is assumed that no bits are available and the device token is only used as an additional check that traffic is coming from a real iOS device.

Now that this information is added to your Approov account, the Approov cloud servers are able to contact the Apple servers to read and update the state. You can confirm that the information has been recorded with:

$ approov devicecheck -get
TeamID: YYYYYYYYY
KeyID: XXXXXXXXXX
Expiry: 12m
Bits: both
Apple Endpoint: Production

If you have selected usage of bits, then Approov sets those bits in order to indicate that a particular device has been banned, and should no longer receive valid Approov tokens. If you have never used the Apple DeviceCheck facility previously then the bits will not be set and so the default will be to allow the allow valid token fetching. If you have used the facility before and some bits may be set then this will cause banning of those devices. In this case you may use the -expiry option when setting the authorization key to ignore settings made more than a certain number of months ago. If the bit setting has been more recent than one month then you will not be able to use this Approov facility on your apps until sufficient time has elapsed.

Permanent Device Banning

As discussed in Banning a Device, it is possible to ban a particular device ID from receiving valid Approov tokens. However, reinstallation of the app on the same device may generate a new device ID and evade the ban. If you are using DeviceCheck then a permanent ban for a particular physical device can be instigated.

Whenever you ban a device ID with DeviceCheck on the account active, the ban will become a permanent ban of the physical device (unless the bit availability has been set to none).

If you have the all Annotation Policy selected then tokens rejected due to a permanent DeviceCheck ban have devicecheck-ban listed as a rejection reason.

Unbanning whatever device ID the physical device is using will also remove the permanent ban.

When a particular device is banned it is across all apps associated with the same Apple developer account, even if these apps are associated with different Approov accounts. This is because Apple stores the bit states on a per-developer account basis. If you are using multiple Approov accounts associated with a single Apple developer then you may select different bits on different accounts to avoid such interference.

Removing the DeviceCheck Key

The DeviceCheck authorization key can be removed from the account at any point, if an admin role is available, as follows:

$ approov devicecheck-remove
WARNING: this will have an immediate impact on your apps in production. If you wish to continue then please enter YES and return: YES
device check information removed

This will disable all lookups of DeviceCheck. Any ban will remain on a particular device ID, but if the physical device is allocated a new device ID due to app reinstallation then the ban will not follow. If the device check key is subsequently set again then the banning of the same devices will be reinstated since the Apple bit state will not have been changed.

Automatic Device Banning

An automatic device banning feature is enabled if both bits are made available when setting the DeviceCheck key, such as the following:

$ approov devicecheck -addAuthKey AuthKey_XXXXXXXXXX.p8 -teamID YYYYYYYYY -bits both
device check information added

In this case the two available bits are used as a counter of the number of times an app has been removed and reinstalled on a device. Each reinstallation will generate a new device ID. However the DeviceCheck bits implement a counter and when this reaches the maximum value of 3 the physical device will be automatically banned. This is because such continual re-installation behaviour is typically associated with some kind of malicious activity. Once banned the abuser will no longer be able to use the device to obtain valid Approov tokens. Non-malicious users would have to uninstall and reinstall the app at least three times before receiving a ban and this would represent very unusual behaviour.

Since the two bits are interpreted as a counter, we do not advise you to use this feature if the DeviceCheck bits have ever been previously used on the account for other purposes more recently than the value of -expiry. Moreover, you should never use the automatic banning feature if sharing a single Apple developer account across multiple Approov accounts or if you have multiple different iOS apps associated with even a single Approov account.

Note that once a device has been banned, the only way to unban it is via the manual Removing Device Ban method.

Google SafetyNet Integration

This section covers the integration between Approov and Google’s SafetyNet attestation feature. It allows enhanced assessment of the integrity of the device, and provides additional signals that Approov uses to check for rooting or modified devices.

Use of SafetyNet requires Google Play Services to be active on the device. Not all Android devices have Play Services installed, or able to support it. Thus you should be careful about assuming that SafetyNet is universally available for your Android user base. Note also that in order to use SafetyNet your app must specify the appropriate packages in the gradle build.

In order to use SafetyNet then you must use an SDK that is version 2.4.0 or later. If this option is used then the Android Approov SDK must make a call to perform an attestation on the device. This needs to be done on the first Approov token fetch after first installing the app. Performing this operation requires additional network connection(s) and CPU processing time, over which the Approov SDK has no control. This can substantially delay the fetch operation on the Android platform by adding up to 3500 ms of additional latency.

How the SafetyNet Integration Works

If SafetyNet is enabled then the Approov SDK initiates an attestation the first time that app is launched after installation. The amount of time that this takes is highly dependent upon the device and can take several seconds. In order to perform this attestation, a SafetyNet API key must be added to your account. The attestation involves analysis of the device filesystem integrity and a communication with Google servers. Upon success an SafetyNet token is provided, which is transmitted to the Approov servers and forms part of the overall enhanced attestation process that it performs.

In order to prevent any possibility of a replay of known good SafetyNet tokens, it contains a nonce value that is generated by the Approov servers. This is checked as part of the overall analysis of the SafetyNet token to ensure that it is a live token generated as part of the current attestation transactions.

The full validity of the SafetyNet token is checked, including analysis of its certificate chain to ensure that the token was definitely issued by Google servers. This does not require any communication between Approov and Google servers.

If there are any issues with the SafetyNet token obtained, then these are reflected in the device property flags that are collected as follows:

  • safetynet-completed: Indicates that a SafetyNet token has been received by Approov.
  • safetynet-fail-token: Indicates that the SafetyNet token is invalid in some way, such as not being signed correctly or the nonce value is not as expected. This almost certainly indicates some kind of hacking attempt.
  • safetynet-fail-integrity: Indicates that the SafetyNet basicIntegrity flag was false. This indicates that the device is likely to have been tampered with in some way, and is likely to be rooted or an emulator.
  • safetynet-fail-profile: Indicates that the SafetyNet ctsProfileMatch flag was false. This means that the device is not running a version of Android that has passed Google’s compatibility testing.
  • safetynet-fail-cert: Indicates that the apkCertificateDigestSha256 field in the SafetyNet token does not match an expected app signing certificate. This test is done in addition to the normal Approov operation which also checks the authenticity of the app. This flag can only be asserted if Android App Signing Certificates have been setup for the account.
  • safetynet-unavailable: Indicates that SafetyNet was not available. This may be because it is not supported on the device, the Google quota has been exceeded or because the app has not been built to include the necessary SafetyNet Google library (see App Build Requirements).

These flags are used in various Rejection Policies to determine if a valid Approov token should be issued. Note that most rejection policies do not make the receipt of a valid SafetyNet token mandatory. However, the policy strict does do so but you should be aware that any devices unable to perform a SafetyNet check will be unable to get a valid Approov token.

Since obtaining a SafetyNet token is an expensive operation, the results are recorded by Approov and are persisted against the device ID. This means that the app should only suffer the extended latency to obtain a SafetyNet token on the initial launch after installation. You might consider prefetching an Approov token in the background to make this delay less obvious.

It might not be possible obtain a SafetyNet token, likely due to one of the following reasons:

  • Device does not support it
  • SafetyNet usage quota was exceeded
  • SafetyNet service was temporarily down
  • Device had poor device network access

In this case subsequent Approov token fetches do not retry, However, each time the app on the device is restarted a fresh attempt will be made until a SafetyNet attestation has been successfully performed.

Note that the SafetyNet API is transmitted dynamically to your running apps. This allows you to change the API key without having to redeploy your apps. Futrhermore, since the API key is not held statically in your app’s APK image it cannot be reverse engineered and attempts made to abuse it to exceed your usage quota.

Getting a SafetyNet API Key

You need to Obtain an API key from Google in order to use the SafetyNet API. This key must then be made available in your Approov account.

There are a number of steps to this process. Firstly, if you have not used Google APIs in your developer account previously then you need to follow the instructions in Getting Started. You will need to enable API access and link it to your developer account in the following screen:

Google API Access Enable

Go to the API Library page in the Google console for your developer account:

Google API Library

Search for and then select the Android Device Verification API. The dashboard screen then appears:

Enable Device Verification

Click the button to enable it. You should then see a screen like this:

Android Device Verification Enabled

This shows a graph of the usage of the API which you may consult later once SafetyNet is in use. Next you will need to obtain a credential (i.e. SafetyNet API Key) to use it. If the Create Credentials button appears, click on it to generate an API key. Otherwise, click the All API Credentials drop-down list, then select the API key that’s associated with your project that has enabled the Android Device Verification API as follows:

Android Device Get Credentials

Whichever route you take to get the API key, you should ultimately end up with a dialog such as this that provides the API key:

Android Device Verification Got Key

Copy and paste this API key as you will need to add it to your Approov account. Remember you ever revoke this API then you will need to update your Approov account with the new one, and Approov SafetyNet attestations cannot be performed in the meantime.

Setting the SafetyNet API Key

Set the SafetyNet API key as follows:

$ approov safetynet -set XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
WARNING: this will have an immediate impact on your apps in production. If you wish to continue then please enter YES and return: YES
safetynet API key set

Once this is set Android devices will immediately try and perform SafetyNet attestations when they connect to the Approov service and they have not done so previously. Note that these means that any existing users of your app will perform a SafetyNet attestation the next time they connect, so consider this when thinking about your initial load against your SafetyNet API quota.

You can always to determine the SafetyNet key that has been set with:

$ approov safetynet -get
APIKey: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Once you have set your SafetyNet API key, we suggest you launch your app using Approov and then check that device’s state to ensure it has a safetynet-completed property. You can also see SafetyNet related flags in the Metrics Graphs.

Removing the SafetyNet API Key

The SafetyNet API key can be removed as follows:

$ approov safetynet -remove
WARNING: this will have an immediate impact on your apps in production. If you wish to continue then please enter YES and return: YES
safetynet information removed

This will immediately stop any usage of the SafetyNet API by your apps. The persisted SafetyNet state for any devices that have conducted a SafetyNet attestation will be retained. If you wish to completely remove any persisted state which may be causing unwanted Approov rejections, for instance, then consider Clearing All Device State.

App Build Requirements

The SDK .aar cannot provide dependencies on the external libraries that it needs to use. Thus if you wish to make use of SafetyNet you must add the appropriate libraries in the dependencies part of your app’s build.gradle file as follows:

implementation 'com.google.android.gms:play-services-base:17.3.0'
implementation 'com.google.android.gms:play-services-safetynet:17.0.0'

If the Approov SDK inside your app is unable to resolve dependencies to the required Google Play services, then the message Google GMS services not available or Google SafetyNet not available will be logged when the Approov SDK is initialized. We suggest you check your integration by launching the app with a SafetyNet API key set and then Getting State of a Device using the device’s ID. If SafetyNet has been successfully carried out then you will see safetynet-completed as one of the properties of the device.

If you are currently using Appcompat in your app then you may be forced to update older compat-v7 versions to allow use of the latest Google Play Services, see this.

Signing Certificate Integrity

The SafetyNet token may include a apkCertificateDigestSha256 claim that provides a SHA256 hash of the certificate used to sign the application. This claim might not be present if the device does not meet even basic integrity requirements. This is in contrast to the Approov app signature analysis which operates even if a device is rooted.

If this claim is present and the signing certificates have been added to the Approov account using approov appsigncert then a comparison is made as an additional check to ensure that the SafetyNet token is consistent with the identity of the calling app. If not then the flag safetynet-fail-cert is set.

Adjusting the SafetyNet API Quota

Performing a SafetyNet attestation causes the device to call a Google API. By default, accounts have a fixed quota of 10,000 requests per day across all apps using the same SafetyNet API key.

Approov will only perform a SafetyNet attestation the first time an app is launched after installation (or after setting the SafetyNet API key, if there is already an installed base of app users). The SafetyNet status is persisted by Approov servers to avoid having to use SafetyNet more frequently. Thus if your typical increase in new users is less than 10,000 per day you can use the standard quota.

If you expect higher traffic than this then you must request an increased quota from Google. When you reach the following questions you can fill them in as follows:

Quota Request

The Approov integration already takes the appropriate measures to minimize the usage of the SafetyNet service.

If you exceed your quota then some devices will not be able to perform a SafetyNet attestation. This is not a problem necessarily (unless you are using the strict rejection policy) as the SafetyNet attestation will be performed the next time the app is restarted and connects to the Approov service. This should help smooth the consumption of your quota. It is only problematic if you are continually exceeding your quota on a day-to-day basis.

Note that there is also a limit of 5 requests per minute from an individual device. However, the design of Approov is such that this limit should never be exceeded.

Managing Key Sets

When an Approov account is created it is allocated a random secret key that is used by default for Approov token signing or encryption. This provides Approov tokens signed using the HS256 algorithm (or A256GCMKW if an encrypted JWE is selected). The HS256 verification uses the symmetric 512-bit account secret key, which needs to be made available to the backend API, to check the validity of the token.

Key sets allow additional keys to be added to an Approov account, which can then be used to sign or encrypt Approov tokens for specific API domains. This allows the use of different keys for different API domains if required. Moreover, key sets also allow access to a much richer set of signing algorithms. In particular, asymmetric signing algorthms (such as RS256) allow the validity of a token to be verified using only the public key. This avoids the security risks associated with needing to add a symmetric key to the API backend (such as with HS256), which could allow valid Approov tokens to be generated if it were to be compromised.

Adding a New Key

A new, randomly generated, keyset key can be added as follows. You can specify the name which you wish to give the key and the algorithm used for signing and encryption, as follows:

$ approov keyset -kid mykey -add RS256
successfully added key

In this case a new key named mykey is generated for use with the RS256 signing algorithm. A random RSA private key is generated by Approov and added to your account.

The following signing algorithm are available:

  • HS256, HS384, HS512: These HMAC signing methods use a symmetric key, with differing hashing algorithms. If you use these then you must be careful to secure the symmetric key used to verify them, since it can also be used to create fresh valid tokens.
  • RS256, RS384, RS512: These use RSASSA-PKCS1-v1_5 asymmetric cryptography, with differing hashing algorithms. The Approov tokens are signed with the private key which can be verified in the backend API using the associated public key.
  • PS256, PS384, PS512: These use RSASSA-PSS asymmetric cryptography, with differing hashing algorithms. The Approov tokens are signed with the private key which can be verified in the backend API using the associated public key. The difference from RSASSA-PKCS1-v1_5 is that there is a random element to the signature, which may be advantageous to differentiate Approov tokens if many are being generated with the same expiry timestamp.
  • ES256, ES384, ES512: These use ECDSA asymmetric cryptography, with differing hashing algorithms. ES256 uses curve P-256 (secp256r1), ES384 uses P-384 (secp384r1), and ES512 uses P-521 (secp521r1). The Approov tokens are signed with the private key which can be verified in the backend API using the associated public key.
  • A256GCMKW: This is the only supported encryption algorithm to generate a JWE rather than a JWS. This uses a symmetric key, so if you use this then you must be careful to secure the symmetric key since not only can it be used to decrypt and verify tokens, it can also be used to encrypt fresh valid tokens.

This article provides a good overview of the different options.

Once a new keyset key has been added, it can be referenced by the -keySetKID option for Keyset Key API Addition.

It is also possible to specify a key length override parameter when specifying an algorithm that uses RSA (RS256, RS384, RS512, PS256, PS384, PS512) or symmetric keys (HS256, HS384, HS512, A256GCMKW).

$ approov keyset -add RS256 -keyLength 4096
successfully added key

The default length for an RSA key is 2048 bits, but it may be overridden to 1024 or 4096 bits. The default length for a symmetric key is 256 bits, but may be overridden to 128 or 512 bits.

Note also that in this case no kid parameter was specified. If this is not provided then the key is named using a simple incrementing counter for the account.

The existing Quickstart Backend Integrations are written assuming the default signing algorithm of HS256 and that the account secret key is being used. You will need to make small alterations to these to support different algorithms and the different manner in which public keys are obtained for keyset keys.

It is only possible to have a maximum of 10 keyset keys at any one time.

Listing Keys

The current keys in the keyset can be listed as follows:

$ approov keyset -list
1 key:
 mykey  alg:RS256  apis:mydomain.com

The algorithm associated with each key is provided, along with a list of any apis that the key is currently associated with for token signing. A given key may be associated with multiple different API domains.

Removing Keys

A keyset key can be removed as follows:

$ approov keyset -kid mykey -remove
key mykey removed

Note that you need an admin role to remove a key from the keyset. Furthermore, you can only remove a key if it is not in use on a particular API domain. If so, then you need to Remove the API Domains first before the key can be deleted. This needs to be done with care as it will have an immediate impact on your production usage.

Getting Public Key PEM

It is possible to obtain the PEM file for a specific key within the keyset. This is the encoded form of the public key for the key specified by the -kid option, in PKIX ASN.1 DER format. The encoded public key is a SubjectPublicKeyInfo structure, as defined in RFC5280, section 4.1. Obtain the PEM as follows:

$ approov keyset -kid mykey -getPEM mykey.pem
$ less mykey.pem
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQU...
-----END PUBLIC KEY-----

Various external tools and API gateways support this format to allow the checking of Approov tokens.

It is only possible to obtain a PEM for RSA and ECDSA key types, that use asymmetric cryptography. The command generates a PEM containing only the public key. This enables token verification but not token creation which means public disclosure of the PEM file does not enable a path to unauthenticated access to your API. It does however mean that external parties can determine the validity of Approov tokens which is undesirable. Depending on your security posture and if this does happen, you may still want to change the token secret for the associated APIs.

Getting Keyset JWKS

It is possible to obtain the JSON Web Key Set for all keys in the keyset as follows:

$ approov keyset -getJWKS keys.jwks
$ less keys.jwks
{
  "keys": [
    {
      "alg": "RS256",
      "e": "AQAB",
      "kid": "mykey",
      "kty": "RSA",
      "n": "4NhUHZSl5ws8...",
      "use": "sig"
    }
  ]
}

Note that you need an admin role to get the JWKS for the key set. This is because this will also obtain any symmetric keys in the key set, and these require rigorous security since they allow creation as well as verification of Approov tokens. For asymmetric RSA and ECDSA keys only the public key is obtained.

Importing Keys

It is possible to import a JSON Web Key into the keyset as follows:

$ less byok.jwk
{
  "alg": "RS256",
  "use": "sig",
  "d": "FumDxNCs...",
  "dp": "mUxVEADBN...",
  "dq": "Yv9xjIj5vOo...",
  "e": "AQAB",
  "kid": "byok",
  "kty": "RSA",
  "n": "05yGbvzgIobbtaeJ...",
  "p": "9_NNlMTz_S5jcxORGz...",
  "q": "2ns2LBc5-1f3m7iI...",
  "qi": "TxLIVbqDsTvmhTgmR..."
}
$ approov keyset -import byok.jwk
private key imported

A kid claim must be present and not be the same as any existing key in the key set. The alg and use claims must also be present and be consistent with algorithms supported by Approov, or else the import request will be rejected.

Note that you need an admin role to import a private key. For an asymmetric key, once the private key is imported it is not possible to export it again. Only the corresponding public key may be exported. Extreme care must be taken to secure the file holding the JWK since it contains the private key and can thus be used to create valid Approov tokens.

If you have multiple Approov accounts, then the importing feature allows you to Bring Your Own Key (BYOK) and share them between multiple accounts. This allows Approov tokens generated by different accounts to use the same Approov protected backend API using a common key. In this case the private key should be generated externally to Approov and then imported into the required accounts. Alternatively, you could make the backend API compatible with multiple different key IDs that it can lookup from the token header)

Message Signing

This is an advanced option that enables a method in the SDK to sign arbitrary messages, using HMAC with the SHA-256 algorithm. This ensures strict message integrity between the client app and the backend API, and is also an additional proof that the requests are truly emananting from an app that has passed the Approov attestation process. Message integrity is also assured by Public Key Pinnng, which we strongly recommend that you implement (all of our frontend integration quickstarts do this). We provide message signing as an advanced option for certain situations where an additional level of integrity assurance is required.

When message signing is enabled the Approov account is assigned a random 512-bit secret that is used for the signing process. This secret key is only transmitted to the SDK if it passes attestation and is provided with a valid Approov token. If the attestation fails, and an incorrectly signed Approov token is sent, then an incorrect message signing secret is also provided so that the app’s message signatures will be incorrect.

The client app should concatenate the relevant parts of a request into a single string. This should then be passed to the signing method in the SDK to obtain the signature. The signature should then be added to the request, typically as an additional http header, before the request is issued. It should always be submitted in addition to the Approov token. Moroever, you should always include the Approov token itself as part of the string submitted for signing as this strongly binds the Approov token to the signature and prevents replay attacks (since the Approov token has a short expiration time). The backend server is able to gather the components of the request and build the same single string as the client and calculate the expected signature, knowing the secret message signing key being used. This should match the submitted signature, or else the message has been tampered with in some way during transit or the originator of the message did not have access to the correct secret key.

A recent RFC provides an outline of the issues with implementing signing on http requests. A consistent approach must be used between the client app and the server about which particular headers to be included, and in a consistent order. Moroever, networking intermediaries may subtly transform the message between the client app and the server in semantically valid ways, but this may mean that the message is no longer bitwise equivalent and message signatures fail. To avoid this, care must be taken to transform elements of the request to some canonical form prior to the signing process on both the client and the server.

Even if you are using message signing to verify requests, you should also pass the Approov token. A check should be made on the validity of the Approov token before checking the message signature. A check on the message signature should only be performed if there is a valid unexpired Approov token with a mskid claim matching the known message signing secret. If there is a valid token without an mskid then the request should be treated as legitimate. The reason for this is that the Approov failover system does not include mskid claims in the tokens it generates and so message signatures cannot be generated (or checked) when the failover is active.

Enabling Message Signing

Message signing can be enabled on the account as follows:

$ approov secret -messageSigningKey change
WARNING: changing the message signing key will have an immediate impact on your apps in production. If you wish to continue then please enter YES and return: YES
key ID: EXTnGx
encoding: base64
RVhUbkd4b01iQ1N3R3Y2cGM4dVdsTEU1UG14S3VOTVhkVDk1dWstb0xPVFZtSEZkdVRueW1lYmRUZWFmR1U3SQ==

An admin role is required. All further Approov token fetches will also transmit the signing secret to the SDK and the key ID for it will appear in the mskid claim in Approov tokens. The generated message signing secret is provided in base64 format. It can also be obtained in other formats.

The command can also be used to change the message signing secret to a new random value if required. Remember that the new secret must be made available to backend systems to do the signature verification.

Getting the Message Signing Key

The current message siging key can be obtained as follows:

$ approov secret -messageSigningKey get-raw
key ID: EXTnGx
encoding: raw
EXTnGxoMbCSwGv6pc8uWlLE5PmxKuNMXdT95uk-oLOTVmHFduTnymebdTeafGU7I

An admin role is required. This example uses get-raw to get the raw secret value which is always 64 characters long. The generated secret only consists of printable characters, to support this.

Note that the key ID, which is included in the mskid claim of Approov tokens, is composed of the first few characters of the raw secret.

You can also obtain a base64 or base64url encoded form of the secret key with get-base64 or get-base64url.

Disabling Message Signing

Message signing can be disabled on the account as follows:

$ approov secret -messageSigningKey clear
WARNING: changing the message signing key will have an immediate impact on your apps in production. If you wish to continue then please enter YES and return: YES
message signing key cleared

An admin role is required. Once disabled, the Approov cloud service will stop adding the mskid claim to new Approov tokens. Furthermore, once running apps receive their next token, the signing secret will be cleared and the message signing method in the SDK will no longer generate signatures.

Prior to going into production you may wish to check the impact of clearing the message signing key, and that this continues to allow backend API operation as expected. This emulates the behaviour expected should the Approov cloud system automatically transition to failover operation.

Generating Message Signatures in the App

A method is provided in the SDK that is able to generate the HMAC signature of a given message (interpreted in UTF8 format). This should only be called after the Approov SDK has been initialized and an Approov token has been successfully fetched:


// generate an HMAC signature of the message
String signature = Approov.getMessageSignature(message);
if (signature != null) {
    <add the signature as a header>
}

// generate an HMAC signature of the message
let signature = Approov.getMessageSignature(message)
if signature != nil {
    <add the signature as a header>
}

The message should be constructed from the concatenation of the parts of the request which should be subject to signing. Make sure that the approach is identical between the apps and the backend so that a consistent message will be constructed, and canonicalized forms are used for any parts of the message subject to legitimate modification by intermediate hops in the communication. Note that we strongly recommend that you always include the Approov token as part of the message.

The result is a base64 encoding of the 256-bit HMAC result. This should be added as an additional header, alongside the Approov token in the request. If the SDK is unable to sign the message then no header should be added. There are a number of possible reasons for this:

  • Message signing has not been enabled for the account
  • The app has failed to fetch an Approov token
  • The Approov cloud failover is in operation rather than the primary system

Message signatures are only supported in version 2.5.0 and later SDKs.

Checking Message Signatures in the Backend

It is important that this message signature checking is only performed in the backend as a step after having checked the Approov token in the normal way, i.e. a correctly signed and unexpired Approov token must be present (that will also be included in the signed part of the request).

A check should then be made to ensure that the Approov token includes a mskid claim. The message siganture should not be checked if this is not present, to allow correct operation with the Approov failover. You should also verify that the key ID matches one held by the backend.

The following provides an example of how the message signature might then be checked in the backend.


try {
    Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
    SecretKeySpec secretKey = new SecretKeySpec(rawSigningSecret.getBytes(), "HmacSHA256");
    sha256_HMAC.init(secretKey);
    String calculatedSignature = Base64.encodeToString(sha256_HMAC.doFinal(message.getBytes()), Base64.NO_WRAP);
    if (!calculatedSignature.equals(providedSignature)) {
        // <Replace this block with the request rejection code>
        Log.e(TAG, "Message signatures do not match, provided=" + providedSignature + ", calculated=" + calculatedSignature);
    }
}
catch (NoSuchAlgorithmException e) {
    Log.e(TAG, "No HMAC support");
}
catch (InvalidKeyException e) {
    Log.e(TAG, "Invalid secret key");
}

The inputs to this process are as follows:

  • rawSigningSecret: The message signing secret obtained from the Approov CLI.
  • providedSignature: The base64 signature as provided on an incoming header. The absence of this header should be considered equivalent to a signature mismatch.
  • message: The overall message gathered from the request, in an ordering consistent with that used by the client app.

Obviously a real example would likely reject traffic with invalid signatures rather than simply log it.

It is not necessary to enforce signature checking on all API endpoints. You may wish to only apply it on particularly security sensitive ones. Of course, there must be consistency between the app and the backend API in these choices.

Android Automated Launch Detection

Approov for Android provides a facility to detect if the app is being launched in an automated way, rather than via the standard launch icon on the device. For instance, this detects if the app is being launched from Android Studio, via an adb shell am start sequence or via monkeyrunner. Typically you would not expect these launches from a production app, and therefore such an automated launch may well be associated with activity that you wish to block. Automated ad clicking commonly uses farms of devices launched and controlled in an automated fashion.

Devices on which automated launching is detected still receive valid Approov tokens (assuming there are no other detected causes for rejection). This is because they still represent untampered instances of the real app running in a standard environment. However, you may optionally select the Annotation Policy of info to force automated launch properties to appear in the annotation of the Approov token.

In order to detect an automated launch it is necessary to provide the Approov SDK with a reference to the Activity. This should be done in the onCreate method of any starting activity for the app. Starting activities are denoted in the AndroidManifest.xml with the appropriate intent filters, for example:

<activity android:name=".MainActivity">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

A simple call to the Approov SDK as follows notifies it of the Activity. It performs analysis on it to determine if there is evidence of an automated activity start. Note that setActivity cannot be called until after the Approov SDK is initialized, but it is assumed that this will be done in the onCreate method of the Application so it will have been completed first.


public class MainActivity extends Activity {
  
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Approov.setActivity(this);

Your backend integration can detect the presence of the properties in the anno claim and react accordingly to requests from the device. The possible properties are as follows:

  • non-standard-launch: Indicates that an Android app is being launched in some non standard way. This might simply be due to the use of a custom launcher app on a consumer’s device, but may be used as a risk indicator along with other factors for automated usage.
  • automated-launch: Indicates that an Android app is being launched in some automated way rather than from the standard launcher. For a production app this is a strong indicator of automation that may be associated with some nefarious use of the app.

Metrics Graphs

Metrics graphs provide both live and longer term summary information about your account usage. They can be used to see the total number of devices that have requested Approov tokens over a time period (and therefore what the usage related costs will be) and also show the failures where particular devices have been denied valid Approov tokens. The graphs provide information about the reasons for any such failures.

The metrics portal can be reached via an approov command. This automatically opens the metrics information in your browser:

$ approov metrics
opening https://metrics.approovr.com/redirect/test-account/usage?access_token=eyJhbGciOiJ…

The URL being opened is shown in the command line and a new browser window is opened with the relevant information. If the browser does not open for some reason (perhaps because there is no default browser is setup) then the given URL can be pasted in another browser window to view the information.

Note that the browser request contains an access token to authorize viewing of the information. Since this is pasted into a browser, it should be handled with care and additional security measures are put in place by Approov around this. It is a specially constructed token that is generated which only provides access to the metrics information and no other aspects of the account. It has a maximum lifetime of 24 hours, with a minimum guaranteed lifetime of 6 hours.

Grafana

The metrics graphs are rendered using Grafana. Please refer to Grafana Getting Started to understand how to use the basic features of Grafana. Note that you will be provided with a fixed set of dashboards showing information from your account and will not be able to edit these dashboards or add new data sources.

A number of different individual dashboards are available for your account, each showing different information and described in subsequent sections. Each dashboard may contain a number of different graphs showing active data from your account. Individual dashboards may be selected using the pull-down menu on the top left hand side of the screen next to the Grafana logo.

Graphs are rendered over a timescale defined in the text box at the top right of the screen. If you click on this then various timescale options are provided. Moreover you can click the refresh button to the right hand side of this initiate a refresh to show the latest data. Options for automatic refresh are also available. Note that times are always shown in UTC, regardless of your local timezone setting. The timescale settings impact all graphs shown on the same dashboard. It is possible to zoom into a graph simply by left clicking on the graph and zooming into the area of interest.

Each graph shows a number of time series, depending upon the graph and the exact circumstances of your account. On many graphs there are numerous time series so it may be difficult to see an individual one. You can restrict the graph to only show a single time series by clicking on it in the legend on the right hand side of the graph. Clicking on it again enables all time series. You can use the control key to perform a multi-select to show an arbitrary set of time series together.

The legend shows the maximum value in the time range being shown. For some graphs an average is also available. Hovering over the graph allows the values to be seen on each selected time series at an arbitrary time.

The authentication method used for Approov Grafana dashboards does not allow the “Share” features to be used. If you wish to share the dashboards you can copy and share the URL generated by the approov metrics command. Note though that the token embedded within this URL has a limited lifetime.

The graphs provide access to a Configuration button which listed available Plugins. Note that these are not available for use in your account.

Metrics Naming

The Approov cloud service generates a number of individual metrics for your account. These represent different activities that are occurring in your account and help you see an overview of usage and any potential issues. There are a number of different types of metrics that are described in the following sections.

Summary Metrics

Summary metrics are used to provide an overview of the status of a particular attestation request received from an app associated with your Approov account.

Metric Name Description
pass Indicates that a valid Approov token was issued.
fail Indicates that a invalid Approov token was issued because a criteria was not met, depending upon the rejection policy selected. Other metrics will provide information about the reason for the rejection.
fail-bad-request Indicates that a request was rejected outright because it was incorrectly formed. Under normal circumstances this should not occur, but could indicate a failed attempt to spoof requests for the account to the Approov servers.

Flag Metrics

Flag metrics provide information about the presence of particular characteristics of devices attesting using your account. These correspond to device property flags that have been extracted from the running device with a prefix flag- added. Furthermore, whenever these metrics are shown they are either prefixed with pass- or fail- depending on whether the overall request was passed or failed.

Whether a given request is rejected or not will depend on the Rejection Policy associated with the account or requesting device. This means that if the security policy is changed then flags previously associated with passes may become fails (or vice versa).

App Metrics

These are metrics generated depending on the app making the request. This allows an easy assessment of the population of apps, or those associated with a particular problematic behaviour. Whenever these metrics are shown they are either prefixed with pass- or fail- depending on whether the overall request was passed or failed. Whether a given request is rejected or not will depend on the Rejection Policy associated with the account or requesting device. Note that app version metrics are only available in the live metrics.

Metric Name Description
app-<os>-<name> The package name of the app that is requesting an Approov token. The app is running on the given os, either ios or and for Android.
appver-<os>-<name>-<version> The package name of the app with its corresponding app version that is requesting an Approov token. The app is running on the given os, either ios or and for Android. This allows tracking of specific versions and the transition to a new version when it is pushed out into the app store.

SDK Metrics

These are metrics generated from statistics collected in each running Approov SDK, which are then aggregated across your entire account. These allow an assessment to be made of the rate of usage of the SDK methods and the prevalence of any errors generated.

Metric Name Description
sdk-calls-fetch-sync Number of calls to made to the synchronous fetchApproovTokenAndWait method in the SDK.
sdk-calls-fetch-async Number of calls to made to the asynchronous fetchApproovToken method in the SDK.
sdk-calls-fetch-config Number of calls to made to the fetchConfig method in the SDK.
sdk-calls-get-pins Number of calls to made to the getPins method in the SDK.
sdk-calls-set-data-hash Number of calls to made to the setDatahashInToken binding method in the SDK.
sdk-calls-integrity-proof Number of calls to made to the getIntegrityMeasurementProof method in the SDK.
sdk-calls-device-proof Number of calls to made to the getDeviceMeasurementProof method in the SDK.
sdk-calls-message-signature Number of calls to made to the getMessageSignature method in the SDK.
sdk-result-success Number of token fetch calls resulting in a SUCCESS / success status.
sdk-result-no-network Number of token fetch calls resulting in a NO_NETWORK / noNetwork status (assuming the app could subsequently get network access to report this).
sdk-result-poor-network Number of token fetch calls resulting in a POOR_NETWORK / poorNetwork status.
sdk-result-mitm-detected Number of token fetch calls resulting in a MITM_DETECTED / mitmDetected status.
sdk-id-<value> Number of token fetch calls made from the Approov SDK with given value ID.
sdk-arch-<platform>-<processor> Number of token fetch calls made from a device with a given processor architecture. The platform may be either ios or android. The processor provides the type of processor used, allowing differentiation between 32-bit and 64-bit systems. Intel architectures for iOS are for the simulator only, whereas Android supports native Intel processor instruction sets.
sdk-version-<value> Number of token fetch calls made from the Approov SDK with given value version number. This is suffixed with -bitcode if the SDK is being used in bitcode mode (for iOS).

Policy Metric

The policy metric is prefixed policy- with the remainder of the metric name providing the name of the rejection policy that was being to the device. This will typically be the default policy for the account, but may be a device specific policy.

Filter Metrics

Filter metrics are prefixed filter- with the remainder of the metric name as defined using the approov filter -add command. Thus these are user defined labels representing particular matches of filtered values of device attributes in Approov token fetches.

Live Metrics

The Live Metrics dashboard allow you to see what is happening in an account on a near real time basis. Information shown in the graphs is updated within a maximum of 2 minutes from the event occurring. New data is made available every minute.

Live Metrics

The live metrics are shown across four independent graphs:

  • Live Passes: This shows Summary, Flag and App metrics from requests that pass and for which a valid Approov token was provided. Metrics are prefixed with pass- indicating this status. The pass summary metric show the total number of passes.
  • Live Fails: This shows Summary, Flag and App metrics from requests that fail and for which an invalid Approov token was provided. Metrics are prefixed with fail- indicating this status. The fail summary metric show the total number of fails. It is important to understand that this shows the properties of the failing device, but these are not necessarily the properties that caused it to fail. Those are shown in the Live Rejections graph.
  • Live Rejections: Shows the Flag that are causal for the rejection to be made. These are prefixed with rejection- to indicate this. This graph also shows the Policy Metric which is being applied and determines which device properties may lead to a rejection.
  • Filter Matches: Shows the Filter Metrics for any matches being made to Device Filters that have been defined.

The y axis for the graphs are in terms of the volume of requests (requests per minute). The same device making multiple requests in a time period will be counted multiple times.

During initial development, when there are no production apps in the account also providing data, the graph can be used for quickly determining if requests are reaching the Approov servers and assessing the response made.

Billing Usage

This dashboard provides an overview of the usage of an account over time showing Summary Pass and non-versioned App metrics. A new entry is generated on each hour. The y axis scale is based on the number of unique device IDs that have been seen since the start of your account’s billing period in the month.

Billing Usage

This figure will grow over the month until it is reset on the “billing day” anniversary each month. The maximum value that the monthly-pass figure reaches during the month is used to calculate the account’s usage invoice for the month. Since billing is calculated only on the basis of passing attestation requests all metrics shown are in fact prefixed monthly-pass.

In addition to the overall figure, metrics are also provided for each app package name that has been successfully used on the account. This allows an assessment to be made between iOS and Android usage, or for different apps associated with the account.

Hourly Metrics

This dashboard provides an overview of the hourly usage of the account, in terms of the number of different device IDs that used the account in an hour period. A new sample is output every hour. It shows Summary, Flag and App metrics. This allows assessment on the level of account usage from hour to hour in terms of the count of different devices.

Hourly Metrics

The upper graph shows devices that were granted a valid Approov token in the last hour, and metrics are prefixed with hourly-pass. The lower graph shows the devices that had at least one failure to receive a valid Approov token in the last hour, and metrics are prefixed with hourly-fail. Pass metrics are restricted to a total and per-app package breakdown. Fail metrics also show flags that are a cause of the failure (i.e. those shown with the rejection- prefix in the live metrics). Note that if a device both passed and failed in the last hour then it will be counted in both graphs.

Daily Metrics

This dashboard provides an overview of the daily usage of the account. The number of devices are counted throughout the day, until reset at midnight UTC. A new sample is output every hour. It shows Summary, Flag and App metrics. This allows assessment on the level of account usage from day to day in terms of the count of different devices.

Daily Metrics

The upper graph shows devices that were granted a valid Approov token in the last day, and metrics are prefixed with daily-pass. The lower graph shows the devices that had at lest one failure to receive a valid Approov token in the last day, and metrics are prefixed with daily-fail. Pass metrics are restricted to a total and per-app package breakdown. Fail metrics also show flags that are a cause of the failure (i.e. those shown with the rejection- prefix in the live metrics). Note that if a device both passed and failed in the last day then it will be counted in both graphs.

Monthly Metrics

This dashboard provids an overview of the monthly usage of the account. The number of devices are counted throughout the month, until reset at midnight UTC on the billing day of the account. A new sample is output every hour. It shows Summary, Flag and App metrics.

Monthly Metrics

The upper graph shows devices that were granted a valid Approov token in the month, and metrics are prefixed with monthly-pass. The lower graph shows the devices that had at lest one failure to receive a valid Approov token in the month, and metrics are prefixed with monthly-fail. Pass metrics are restricted to a total and per-app package breakdown. Fail metrics also show flags that are a cause of the failure (i.e. those shown with the rejection- prefix in the live metrics). Note that if a device both passed and failed in the last month then it will be counted in both graphs.

SDK Metrics

This dashboard shows live SDK metrics that are being collated from running Approov SDKs in apps associated with the account. These are aggregated across all SDKs with a new sample being generated every minute. These metrics are not directly associated with a pass or fail.

The metrics are shown across three independent graphs:

  • SDK Token Fetches: Shows the sdk-result metrics. These in particular can be used to determine if there are any widespread issues affecting running SDKs.The vertical scale is of succeeding or attempted token fetches. Note that if a particular SDK instance is without network for an extended period while trying to perform fetches then when it reconnects the count of attempts made is associated with that connection time, which may cause a spike in the graph for sdk-result-no-network or sdk-result-poor-network results.
  • SDK Calls: Shows the sdk-calls metrics. These are related to counted calls made in the SDK, and will typically be larger than the number of actual Approov token fetches. For instance, calls to get an Approov token when one is already cached are counted here.
  • SDK Libraries: Shows the sdk-arch and sdk-id metrics. This shows the particular architectures and library IDs that are in use.

SDK Metrics

Exporting Data

It is possible to export raw graph data into a CSV file using the menu available on the right click button on each graph, as follows:

Export CSV

Service Monitoring

Approov provides facilities that allows monitoring of the status of your account. A healthcheck API endpoint is supported, along with monthly or even daily summaries of usage and notification emails if there is a certificate problem with one of your endpoints.

Summary Emails

Summary emails can be sent automatically at the end of each billing month. This is typically on the anniversary day within the month of your signup to the Approov service. Typical emails are of this form:

Summary Email Example

Information provided is as follows:

  • Monthly Usage: Provides an overview of the usage of the account in the last month, based ont he monthly endpoint of the information in Billing Usage
  • Security Policy: A reminder of the Security Policy that is currently set for your account. This directly impacts which devices are passed and which are failed.
  • Passing Devices: Provides an overview of the properties of the devices which were passed during the month, based on the monthly summary of the information in Monthly Metrics.
  • Failing Devices: Provides an overview of the properties of the devices which failed during the month, based on the monthly summary of the information in Monthly Metrics.
  • Rejection Flags: Provides a list of all of the device property flags that are being collected when an Approov token fetch is performed, and a short descripiton of each. This also shows which will cause a rejection.

The email should be received shortly after midnight UTC on your billing day. The email is copied to all those on the recipient list. The next section shows how you may update the recipients. Shortly after receiving the summary email you will also receive an invoice or automated credit card charge reflecting the usage shown in the summary email.

API Monitoring

The Approov cloud service is able to monitor your API endpoints to ensure that they are both accessible and that the certificates presented match one or more of the pins you have set in your account. The endpoints are checked every 15 minutes, and a notification email is sent if a problem is detected. This will list each of the monitored API domains that are experiencing an issue.

When you add an API domain monitoring for it will be activated automatically, unless no pin was added or one was added via local access (implying the API endpoint is not generally visible on the Internet). Note that notifications can only be sent if your account’s email recipients list has been setup with one or more entries.

You can always set a new API for monitoring as follows:

$ approov monitoring -addAPI mydomain.com
API monitoring updated successfully

An admin role is required. If the API is not accessible on the standard port of 443 you can use the -port option to select monitoring on a different port.

If an email is sent then, by default, no further ones will be sent for 24 hours. However, you can override this behaviour by issuing the following command:

$ approov monitoring -resumeAPINotifications
API monitoring notifications resumed

You will then receive an email again if there is a further problem after the APIs are checked on the next (or a subsequent) 15 minute cycle.

Monitoring for a specific API domain can be removed as follows:

$ approov monitoring -removeAPI mydomain.com
API monitoring updated successfully

This might be required if the API domain is not accessible from the Approov cloud service, or is not part of your production system and you don’t wish to monitor it continuously.

Managing Email Recipients

When your account is first created there are no email addresses allocated for receiving the summary emails. You may add a new recipient as follows:

$ approov monitoring -add ops-monitoring@mydomain.com

Be careful with the addition of email addresses as these are not verified at the time of addition. It is possible to have up to 10 different monitoring email recipients.

You can retrieve the current settings at any point as follows:

$ approov monitoring -get

Producing a response such as:

monitoring emails will be sent to:
  me@mydomain.com
  ops-monitoring@smydomain.com
summary frequency: monthly
emergency contact: Email at ops@mydomain.com, out of hours cell +1 23456789

Email recipients can be removed at any point with:

$ approov monitoring -remove ops-monitoring@mydoman.com

Setting Summary Frequency

By default only a monthly summary email will be sent. However, it is also possible to opt into a daily summary email that is also sent soon after midnight UTC. It provides a summary of the passing and failing devices from the day, representing the daily endpoint of the data in Daily Metrics.

Opt into daily emails as follows:

$ approov monitoring -selectDailySummary

You may always return to monthly emails only with:

$ approov monitoring -selectMonthlySummary

Emergency Contact

A facility is provided to allow you to set an emergency contact. This will allow Approov to contact your operations team in an exceptional circumstance, such as a major Approov outage or if we detect a serious problem with your account. Ideally therefore you should provide some mechanism to allow us to contact your operations team out of hours.

You can specify a string containing contact information with:

$ approov monitoring -setEmergencyContact "Email at ops@mydomain.com, out of hours cell +1 23456789"

Remember you can always contact our operations team using the technical support portal at https://approov.zendesk.com.

Healthcheck Endpoint

The Approov cloud service incorporates an always-on health monitoring system which actively monitors the state of various internal cloud server components, reporting the overall health state and operational readiness of the primary service. This has an externally accessible API for determining the system health for your account. You can retrieve the URL for this endpoint as follows:

$ approov monitoring -getHealthCheckURL

This provides the URL that you should use for checking your particular account health, e.g.

https://healthcheck.approovr.io/healthcheck/att-my-account

Note that it is common for account names to be prefixed with att-, as shown here. You can query this endpoint to determine the system health as follows:

$ curl -X GET https://healthcheck.approovr.io/healthcheck/att-my-account

This endpoint will return a “200 OK” HTTP response with a JSON body including a HealthState key with value initializing, passed or failed. You would normally expect:

{
  "HealthState": "passed"
}

You can regularly poll this endpoint if you wish to determine the system heath. We do not recommended that you poll more than once a minute. The possible states are as follows:

  • initializing: Appears temporarily after a service restarts one or more components and indicates that the system is gathering data to determine the health status. When this operation is complete, the health monitor will report a passed or failed health state as appropriate.
  • passed: Indicates that the system is up and running correctly. All operations can be used as normal.
  • failed: Indicates that the system has encountered a fault in one or more of its components. The administration APIs may be down which means the service cannot be administered using the approov command line tool. In the unlikely event that the service is unhealthy, the health monitoring system will report a passed state as soon as the system becomes healthy again.

Note that the endpoint only returns the health of the primary service. If there is a problem with the primary service then the failover system is automatically enabled, as described in Cloud Server Redundancy. This means that even if the primary system is being reported as being unhealthy then it is highly likely that Approov tokens will still be being server by the system. Note that if the health endpoint itself is down then it is not possible to determine the system state. However, since this endpoint is not itself served by the primary system and is independent of it, the likelihood is that it remains fully operational.

User Management

It is possible to provide access to your Approov account (via the approov CLI) to other members of your team.

Best Practice

When a new account is created the account holder is issued with dev and admin roles. One the capabilities of the admin role is the ability to add new users, with specific roles.

In a larger organization where multiple personnel need to interact with the Approov service, we expect that there will be some internal control of the access to Approov. We recommend that only a single individual, or small restricted group, should have access to the admin role. We suggest that dev roles are created for each of the individuals that are involved in the development of the apps that use the Approov service. These tokens allow access to all of the facilities required for app development, without more dangerous privileges that might impact apps that are live in production. The dev user roles can be issued to named individuals, preferably for a timescale that represents their likely involvement. Access can be revoked by the administrator at any time.

For larger and more complex teams and projects we recommend having multiple Approov accounts to provide enhanced insulation between development and production operations. If this is a requirement then please contact Approov support.

User Roles

There are four different types of role may be used with the approov command line tool. These are dev, admin, delegate and automation.

Admin Role

An admin role has additional privileges that are not available for the dev role as follows:

  • Removing app registrations that do not have an expiry date. Typically, this type of registration should be reserved for apps in production and so the removal of such registrations is protected.
  • Removing multiple app registrations in single command invocation using the -removeMatching option.
  • Modifying the security policy applied to the whole account. If this is changed then it could cause invalid Approov tokens to be sent to a range of different users that might cause a partial outage event.
  • Removing or modifying the set of API domains and pins for the account. If these are changed incorrectly then connection may be denied in production apps via an incorrect pin, or if an active API domain is accidentally removed then it will no longer receive valid tokens. All these actions could result in an outage event. Note that new API domains can be added with a dev role as this does not carry a risk of outage.
  • The creation, revocation and listing of user roles as discussed in this section.
  • Creating long lived Approov tokens for server-to-server communication or testing.
  • The extraction and update of the account secret key. This secret must be considered to be extremely sensitive since its possession allows arbitrary valid Approov tokens to be generated.
  • Removing Android app signing certificates.
  • Adding or removing Apple credentials for devicecheck usage.
  • Adding or removing Google SafetyNet API keys.
  • Removing or importing keys in the keyset.
  • Exporting the JWKS for the keyset.

Delegate Role

The delegate role has a more limited set of rights, and it will only ever be required in special circumstances. It is used when a 3rd party (who also has their own Approov account) is responsible for developing and registering the app that will be used to access endpoints controlled by this account. The privileges of the role are as follows:

  • Being the destination account for registration cloning using the registration command with the -cloneTo, -cloneToAccounts or -cloneToAllDelegateAccounts options.
  • Obtaining the SDK config using the approov sdk -getConfig command.
  • Managing the app signing certificates with the approov appsigncert commands.
  • Managing any devicecheck configuration with the approov devicecheck commands.
  • Managing any safetynet configuration with the approov safetynet commands.

Note that the delegate role provides no rights to get the account secret key, or keyset keys, associated with the account.

Automation Role

The automation role has a very limited set of rights. It is intended to support automated scripted use of the approov CLI, especially for Continuous Integration (CI) build systems (see Automated Approov CLI Usage.

  • Downloading the SDK itself using the approov sdk -getLibrary command.
  • Obtaining the SDK config using the approov sdk -getConfig command.
  • Creating new app registrations with approov registration -add.
  • Getting the current set of APIs and their pins with approov apis -getAll, and associated api and pin commands that only read the API and pinning state. This also includes approov api -check.

Note if there are any other operations you would like to perform from your build and other automation scripts using an automation role, then please contact Approov support.

Adding New User Roles

Additional user roles may only be issued if you have access to an admin role. Here is an example of issuing Approov access to a new user with dev role privileges:

$ approov users -add bob@mydomain.com
WARNING: you are adding dev role access to account myaccount for bob@mydomain.com (bob)
If you wish to continue then please enter YES and return: YES
onboarding email has been sent to bob@mydomain.com

The -add option has a parameter of the user email. By default the new user role will have the same duration as the admin role used to create it. Moreover the new user role will be password protected (unless overridden with the -noPassword option). The user will receive an Approov Onboarding email with instructions of how to initialize access and they will be invited to set their password.

By default a dev user role will be created. This has limited privileges as discussed in the previous section. A new admin role may be created as follows, in this case with a shortened validity period of one week.

$ approov users -add boss@mydomain.com -admin -expireAfter 7d
WARNING: you are adding admin role access to account myaccount for boss@mydomain.com (boss)
If you wish to continue then please enter YES and return: YES
onboarding email has been sent to boss@mydomain.com

The -expireAfter parameter will normally be specified in terms of the number of days that access will be available for, but years (y) or hours (h) may also be used. Note that it is not possible to generate a user role that has an expiry time after that of the admin role used to create it.

A user name can also be associated with the role. By default this is derived from the part of the email address before the @. You can override this using the -userName option. Quotes must be used around the parameter if you wish to use spaces in the user name.

A new delegate user role may be created as follows:

$ approov users -add appdev@theirdomain.com -delegate
onboarding email has been sent to appdev@theirdomain.com

The delegate role can be provided to an independent app developer, who will then be able to use it to clone registrations from their own Approov account.

Note that there is currently a maximum limit of 25 user roles that may be live for any individual Approov account. If this limit is reached then old unused user roles should be revoked to allow the creation of new ones.

Access Expiry Reminders

Approov will send access expiry reminder emails to the holder of the user role. These are sent soon after midnight UTC daily for the few days prior to the expiry to remind the user that their access is about to expire. No further messages are sent if access is revoked or reaches its expiration.

Note that you will also receive expiration reminders about your primary user roles provided when you first initialized access to your Approov account. If you have a paid plan then you should receive a new onboarding email from Approov shortly after the reminder emails are issued.

Listing User Roles

The available user roles can be listed as follows:

$ approov users -list
3 user roles:
  admin-5794 me@mydomain.com, A N Other, expires 2029-05-08 15:01:05
  dev-0639   me@mydomain.com, A N Other, expires 2029-05-08 15:01:05
  dev-1234   bob@mydomain.com, bob, expires 2029-05-08 15:01:05, password protected

This command output provides the information about the active user roles with a unique ID for each. The first part of the ID is the role, which may be dev, admin or delegate. Other information includes the email addresses, user name, expiry date and if password protection is enabled.

Revoking User Access

In some cases it is desirable to be able to revoke the use of a specific user role before its expiry time. This may be necessary if there is a concern that the access has been compromised or the individual that was provided access has left the project. A user role can be revoked as follows:

$ approov users -revoke dev-1234
WARNING: you are revoking dev-1234 for bob@mydomain.com, bob, expires 2029-05-08 15:01:05
If you wish to continue then please enter YES and return: YES
user access dev-1234 revoked

The user role ID provided as the parameter can be obtained using the -list option. Revocation can take up to 30s. After revocation completes, attempts to use the role will result in an authorization error, e.g.

$ approov registration -list
your access is revoked or expired - contact your Approov administrator
error: Forbidden, while getting management token status

Note that it is not possible to revoke the user roles issued by Approov when you first signed up. If you feel that your access may have been compromised, then please contact Approov support who are able to revoke these roles and then provide new ones.

Automated Approov CLI Usage

You may wish to use the Approov CLI from within automated scripts, perhaps on remote runner machines for Continuous Integration (CI) systems. In this case the interative approov role mechanism may not be appropriate, since it requires a user to type in the password and the session only lasts for one hour. Thus a mechanism is provided whereby an automation role management token can be defined in a local environment variable to provide Approov account access. This will not be password protected.

An automation role management token has limited rights, but should be sufficient for the operations required in a build environment.

Management tokens must be considered to be sensitive secrets since they allow access to your Approov account. Take care with security when setting these up. Never log them and never commit them to source code repositories.

Creating an Automation Management Token

You should create an automation management token for the purposes of the scripted access. An email address must be provided, for the user that is the custodian of the management token. We suggest you override the user name with information about the intended purpose, or the machine that the management token is going to be used on. For instance:

$ approov users -add me@mydomain.com -userName "CI Machine" -automation
WARNING: you are adding automation role access to account myaccount for me@mydomain.com (CI Machine)
If you wish to continue then please enter YES and return: YES
automation management token written to automation-1234.tok
set this in an APPROOV_MANAGEMENT_TOKEN environment variable on the machine that requires it

This writes the automation management token to the file automation-1234.tok, in this case. Follow the instructions for Linux, MacOS or Windows to set the APPROOV_MANAGEMENT_TOKEN environment variable.

If you have multiple different build machines then you could consider having a differently named automation managament token for each one. They can then be independently revoked if required. Moreover, any app registrations made will be tagged with the management token name.

If you have also performed an approov init for the same user that is using an automation management token set with APPROOV_MANAGEMENT_TOKEN then you will get a warning on approov CLI command invocations. This reminds you that the APPROOV_MANAGEMENT_TOKEN is usurping the role that would normally be selected. We generally encourage you to not issue approov init for users or machines that will only be using an automation token. You can remove initialized roles by removing the .approov file in the user’s home directory.

Automation Setup on Linux

You can do this easily with the following command:

$ read -r APPROOV_MANAGEMENT_TOKEN < automation-1234.tok; export APPROOV_MANAGEMENT_TOKEN

The parameter automation-1234.tok should point to the file containing the development management token that you received on signup. You can test the environment variable was set by issuing an approov whomai command.

Note that the environment variable APPROOV_MANAGEMENT_TOKEN will only be set while this shell is running. If you want to make the setting more permanent then you can edit your ~/.bashrc file (or equivalent for other shells) and add the line:

APPROOV_MANAGEMENT_TOKEN=eyJhbGciOiJIUzI1NiI…

The string for your development token should be copied from the automation-1234.tok file. Alternatively you can run the read command above in the context of your shell startup. Now any newly created shells have the management token available in the environment so that it is not necessary to make it available on each approov command invocation.

Automation Setup on MacOS

You can do this easily with the following command:

$ read -r APPROOV_MANAGEMENT_TOKEN < automation-1234.tok; export APPROOV_MANAGEMENT_TOKEN

The parameter automation-1234.tok should point to the file containing the development management token that you received on signup. You can test the environment variable was set correctly by issuing an approov whoami command.

Note that the environment variable APPROOV_MANAGEMENT_TOKEN will only be set while this shell is running. If you want to make the setting more permanent then you need to edit your shell initialization file. This is ~/.bashrc for versions prior to Catalina, or ~/.zshrc since Catalina which uses the zsh by default. If you are using a non-standard shell then you will need to consult its documentation. Add the line:

export APPROOV_MANAGEMENT_TOKEN=eyJhbGciOiJIUzI1NiI…

The string for your development token should be copied from the automation-1234.tok file. Alternatively you can run the read command above in the context of your shell startup. Now any newly created shells have the management token available in the environment so that it is not necessary to make it available on each approov command invocation.

Automation Setup on Windows

Open the advanced settings page:

Windows Advanced Settings Page

Then click on the “Environment Variables” button. This opens up another dialog where you can click on the New for user variables to add a new environment variable. The token should be put in the user, rather than system, variables so that it is not accessible to other users of the same machine.

alt_text

The development token string should be copied from the automation-1234.tok file.

Command shells created after setting the value and closing the dialog will have the management token available in the environment so that it is not necessary to make it available on each approov command invocation. You can test that this is correctly setup with an approov whoami command.

Retrieving an Existing Automation Management Token

If you have previously created an automation role management token then you can retrieve its value again as follows. Firstly, list the user roles to find the role ID value (on the left hand side of the listing):

$ approov users -list
...
automation-1234 me@mydomain, CI Machine, expires 2021-12-04 11:47:11
...

You can then obtain the management token itself using the role ID:

$ approov users -getManagementToken automation-1234
management token written to automation-1234.tok

Offline Security Mode

This section discusses the Approov feature that allows the SDK to prove to a remote hardware device, not directly connected to the Internet, that it is a genuine instance of a particular app.

Use Case

This feature is useful for specific use cases where the mobile device and/or some other remote hardware being commanded by an app may not have a continuous Internet connection. Approov attests itself in the normal way and accesses an API, but additional step for this flow causes a measurement of the app integrity to be taken. This is included in some communication from the backend API to the remote hardware. This will include an encrypted form of the measurement that only the remote hardware is able to decrypt. The remote hardware is then able to know the value of the prior measurement made on the app. An offline attestation process between the app and the remote hardware then proves that the app is able to reproduce the measurement without actually transmitting it. This gives assurity to the remote hardware that it is being commanded by the same app that was earlier measured. This prevents an attacker from commanding the remove hardware using any other client software.

Note that this feature must be enabled in the Approov cloud service before it can be used from an app. Contact Approov support if you are not sure of the status or wish to perform a trial of the feature. It is not provided in our standard Approov commercial package.

Operational Flow

The following provides an overview of the steps required to obtain and use a measurement proof using the offline security feature. The first stage is the app obtaining a measurement:

  1. A special Approov token fetch must be performed that also performs a measurement. This takes the API domain to which the measurement is to be sent with the suffix ?measurement. The fetched Approov token will contain additional information for the collected measurements. The domain must have encrypted JWE tokens enabled, so that the measurements cannot be read by any 3rd party if they are somehow able to intercept the request.
  2. During the Approov token fetch, a full app Integrity Measurement (IM) and a Device Measurement (DM) are made by the SDK. These are both derived from very similar analysis and data as the main measurements required to obtain a token. The IM is a 256-bit HMAC result that encompasses all aspects of the app and mobile device, but is designed to always produce a stable result from the same app on the same mobile device, even if the app or the whole mobile device is rebooted. The DM is also a 256-bit result but is specifically designed to only include data sources that are device specific, or specific to data stored by the app in internal storage. This means that this hash should be stable even if the app is updated (including an update to the version of the Approov SDK that is embedded within it). A property of both the IM and DM is that they are salted by a nonce value. This means that the actual hash values are different for each Approov attestation, even if the app and its environment have not changed.
  3. The Approov cloud evaluates the attestation request as normal. The only difference is that the generated Approov token will have an additional claim providing encrypted forms of the IM, DM and also the Measurement Proof Key (MPK). The MPK is a 128-bit key that is dissolved into the code of a particular version of the SDK and is also known by the Approov backend.
  4. The app will pass the Approov token containing the measurements to the backend API. The backend evaluates the request, checking the validity of the Approov token. If the verification checks are passed, then some form of measurement token is created to pass to the remote hardware, containing the measurements from the Approov token. This will be encrypted by a public key known to the backend, with the decrypting private key held securely in the remote hardware. This means that only the remote hardware is able to know the contents.
  5. As an additional result of performing a measurement during an Approov token fetch, a Measurement Configuration (MC) is also provided as part of the result. This is a binary data blob that must be held in local storage. It contains the configuration information that will be used by the app to reproduce integrity and device measurements in the future. The contents of this data are signed (in the sense that any modification will impact the measurement results) so an attacker cannot tamper with it. This is saved into persistent storage of the app. Furthermore, the encrypted measurement token provided by the API is also persisted in the local storage of the app.

The next step (which may be repeated an arbitrary number of times) is to perform a measurement proof between the app and a remote hardware device:

  1. Methods (getIntegrityMeasurementProofand getDeviceMeasurementProof) are provided in the Approov SDK to allow a measurement proof to be made, salted by a nonce value provided by the app. This should be different each time, to prevent replay attacks. The measurement proof methods require the MC file that was saved earlier. Since this is held in persistent local storage the app can be closed, and indeed the mobile device rebooted, between measurements and the same result will be obtained if no tampering of the app has occurred. Crucially, this entire measurement proof process does not require any Internet access.
  2. The measurement proof result is transmitted to the remote hardware device over some local communication link, such as Bluetooth.
  3. The measurement token, that was stored earlier, and contains the encrypted measurement is also communicated to the remote hardware device over the local communication link.
  4. The remove hardware is able to check any measurement proofs since it has access to the known good measurement values decrypted from the measureent token. Thus it can determine if the same app instance is making the request as was originally validated by the API backend. Only the remote device is able to decrypt the measurement token since only it is in possession of the required private key.

Backend Integration

In order to support offline mode there are some requirements on the backend integration for the API domain that is responsible for issuing measurement tokens to the remote hardware. A key requirement is that some Public Key Infrastructure (PKI) needs to be in place with the remote hardware. This means that the backend API can encrypt the measurement token and only the specific remote hardware (or class of remote hardware) should be able to decrypt the contents. Of course this depends on keeping the private key in the remote hardware secure, but this is beyond the scope of Approov.

The backend API must check the Approov token in the normal way, but then extract the imh (Integrity Measurement Hash), dmh (Device Measurement Hash) and mpk (Measurement Proof Key) out of the Approov token and put the values into the measurement token.

Encrypted JWEs must be used on endpoints to which measurements are transmitted for additional security.

Remote Hardware Integration

It is envisaged that the app will communicate with a remote hardware in order to command it in some manner. This will require a combination of a valid measurement proof and likely other user credentials to be accepted by the remote hardware. In other words, it is checking that it is being commanded by the right software and by the right user. The exact channel of communication is independent of the Approov feature, but a typical choice is Bluetooth.

A valid measurement proof indicates that the Approov SDK is able to reproduce the integrity measurement value that was calculated earlier when the measurement was first obtained. Each measurement is salted with a 128-bit nonce value to prevent replays of prior results. A measurement is actually an HMAC of the measurement salted by the nonce. The method of choosing this nonce is not defined by Approov.

The remote hardware implementation must do the following:

  1. Decoding Measurement: The measurement token transmitted to the remote hardware should be decrypted by the hardware using its private key. This gives it access to the Integrity Measurement (IM) and potentially also the Device Measurement (DM). The Measurement Proof Key (MPK) also needs to be decrypted as it is used in the measurement proofs.
  2. Checking Measurement Proofs: The Approov SDK calculates the integrity measurement proof HMAC result. It does not need Internet access to be able to do this and the overall calculation should not take more than approximately 100ms. The integrity measurement is recalculated on the fly during this call and used to calculate the result of HMAC(MPK, nonce || IM). The Measurement Proof Key (MPK) is dissolved in the obfuscated code of Approov and provides a further layer of security. The result is a 256-bit value called the Integrity Measurement Proof (IMP). This IMP value is transmitted to the remote hardware and it must perform exactly the same HMAC calculation. Note that a Device Measurement Proof (DMP) can be calculated in exactly the same manner.
  3. Restricting Access: Once the IMP (and/or DMP) have been calculated they can be compared with that provided by the SDK. If they do not match then some aspect of the app or its runtime environment has changed since the original measurement. This would normally result in an access denial. Some useful error state should be returned to the app, so that it can suggest to the user that they will need to redo the original measurement process and verification by the API backend.

Requesting a Baseline Measurement

As discussed previously, the first stage in making an Approov measurement is to request a token in measurement mode. Example code to do this is as follows:


Approov.TokenFetchResult approovResult = Approov.fetchApproovTokenAndWait("api.myservice.io?measurement");
if (approovResult.isConfigChanged())
    saveApproovConfigUpdate();



let approovResult = Approov.fetchTokenAndWait("api.myservice.io?measurement");
if approovResult.isConfigChanged {
    saveApproovConfigUpdate()
}

This is a standard token fetch call, except for the ?measurement suffix of the provided domain. This forces a measurement to occur, even if there is a previously cached and valid Approov token. The expectation is the special measurement token will be sent to the API domain api.myservice.io.

Persisting the Measurement Configuration

Next, the measurement configuration obtained from this measurement must be saved to local app storage. This code provides an example approach:


if (approovResults.getStatus() == Approov.TokenFetchStatus.SUCCESS)
    // check that we obtained a configuration measurement (this should always be the case
    // but we check in case there has been an error)
    byte[] measurementConfig = approovResults.getMeasurementConfig();
    if (measurementConfig == null) {
        <error handling>
    }

    // save the measurement configuration to local storage
    try {
        FileOutputStream outputStream = getApplicationContext().openFileOutput("measurement_config.bin", Context.MODE_PRIVATE);
        outputStream.write(measurementConfig);
        outputStream.close();
    } catch (IOException e) {
        <error handling>
    }
}

if approovResult.status == ApproovTokenFetchStatus.success {
    // check that we obtained a configuration measurement (this should always be the case
    // but we check in case there has been an error)
    if approovResult.measurementConfig == nil {
        <error handling>
    }

    // save the measurement configuration to local storage
    let URLs = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
    let measurementConfigURL = URLs[0].appendingPathComponent("measurement_config.bin")
    do {
        try approovResult.measurementConfig!.write(to: measurementConfigURL)
    } catch {
        <error handling>
    }
}

This saves the configuration to the local file measurement_config.bin. A saved measurement configuration is required in order to perform subsequent proofs that the integrity measurement has not changed. By saving the measurement configuration the app is able to perform such checks even if the app is restarted.

Getting a Measurement Proof

At some point later, a measurement proof may be required to communicate the app’s authenticity to a remote hardware. First, the measurement configuration must be loaded from local app storage again. Example code is as follows:


// read the measurement configuration from local storage
byte[] measurementConfig = null;
try {
    InputStream stream = getApplicationContext().openFileInput("measurement_config.bin");
    DataInputStream reader = new DataInputStream(stream);
    measurementConfig = new byte[stream.available()];
    reader.readFully(measurementConfig);
    reader.close();
} catch (IOException e) {
    <error handling>
}

// read the measurement configuration from local storage
let URLs = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
let measurementConfigURL = URLs[0].appendingPathComponent("measurement_config.bin")
var measurementConfig : Data? = nil;
do {
    measurementConfig = try Data.init(contentsOf: measurementConfigURL)
} catch {
    <error handling>
}

Once the measurement configuration is available, a measurement proof calculation can be performed as follows:


// perform the integrity measurement proof calculation
byte[] integrityProof = Approov.getIntegrityMeasurementProof(proofNonce, measurementConfig);
if (integrityProof == null) {
    <error handling>
}

// perform the integrity measurement proof calculation
let integrityProof = Approov.getIntegrityMeasurementProof(proofNonce, measurementConfig!)
if integrityProof == nil {
    <error handling>
}

This generates a 32 byte result in the integrityProofvariable. The result of this is a combination of the measurement taken earlier when the Approov token was fetched, and a 16-byte proofNonce value provided by the application. The choice of the nonce is beyond the scope of this document, but it should be varied on each measurement proof.

The measurement proof value can then be transmitted to the remote hardware, along with any other relevant credentials as part of any command from the app to the remote hardware The hardware is able to evaluate this to determine if the app has calculated the same integrity measurement value as previously. Since a non-replayable HMAC proof value is being transmitted, any attacker able to steal data from the channel will not be able to infer the actual integrity measurement value or replay the data later.

If any of the characteristics of the app’s integrity changes, then the computed value will differ and access will be denied. This occurs if there is any change to the app itself, or if the runtime environment has changed. For instance if the app is now under debug, or subject to analysis by a framework, then the measurement will be altered. The measurement may also change if the operating system version of the device on which the app is installed is upgraded.

Note that the Approov SDK also includes a getDeviceMeasurementProof method. This is used in exactly the same way, but only measures attributes of the mobile device on which the app is running. Thus this calculation will not be impacted by any update to the app (or device’s OS) that is being attested.