Secure Strings
This is the underlying SDK feature that implements Approov Runtime Secrets Protection. It provides a secure storage capability for secrets or access tokens held by an app. A facility is also provided to predefine secure string values using the Approov CLI. These values are only made available to running apps that pass the selected rejection policy. This provides the usual protections provided by Approov so that only apps passing the attestation process can obtain access to the secrets.
The feature provides an alternative to the use of Approov tokens when Backend Integration is not possible for whatever reason, perhaps because the backend API is not controlled by the same organization as the frontend app. The two approaches can be used together if required, protecting some backend APIs with Approov tokens and using secure string secret storage for other purposes. In general we suggest you use Approov tokens wherever possible, because they are short lived ephemeral tokens that provide excellent security characteristics. However, secure secret storage provides a viable alternative in other cases that can leverage all of the same Approov app integrity checking capabilities.
The typical use cases are as follows:
-
Predefined Secure String: Some APIs might require an API key or secret in order to access the services. If this value is shipped in the app then it is easily possible to extract it using reverse engineering tools. Moreover, even if the value is obfuscated using an app hardening process it can still be extracted by a Man-in-the-Middle (MitM) proxy between the app and the backend. Predefined secure strings provide an easy solution to remove such secrets from the shipped app code. Instead, the API keys are added as predefined secure strings to your Approov account using the Approov CLI and with key names of your choosing. At runtime the app can then try and retrieve the secured values from the Approov SDK, by requesting the values associated with your chosen key names. This causes the Approov SDK to contact the Approov cloud service and perform the required attestation checks. It is only if these attestation checks pass that the secure strings are delivered to the app. These secrets remain protected at rest by Approov, and accessing them is subject to further attestation checks after a short time interval. Secrets, such as API keys, that need to be transmitted to a backend API need to be protected in transit using either pinning or managed trust roots to ensure they cannot be intercepted at that point. Note that a further advantage of this approach is that the secrets can be updated dynamically without any need to reissue a new app version through the app store.
-
App Instance Secure Strings: The feature also allows secure storage of app specific secret strings. These values are never transmitted to the Approov cloud. Instead they are encrypted at rest in app specific persistent storage using a device specific encryption key. This encryption key is only made available to the app at runtime after passing the Approov attestation checks. Thus these values are secured against extraction when the app is not active, and the temporary decryption of the values when the app is running is subject to passing the Approov attestation. A typical use case is the secure storage of access and refresh tokens obtained from an account login event. These need to be presented on API requests, but need to be protected at rest and in transit to prevent an attacker capturing them to script accesses against API endpoints. The app specific strings can can be protected in transit using either pinning or managed trust roots to ensure they cannot be intercepted at that point.
You should not use the secure strings feature for general storage in your app as accessing entries will sometimes be subject to delay. For example, the initial use of the feature requires a full attestation with its associated network access to Approov servers adding latency and the possibility of failure due to the lack of network connectivity. Once access has been granted, secure strings can normally be accessed without further network activity for a period of about 5 minutes. However, once the temporary access expires another full attestation will be required. You should really only use the feature for holding secrets that need to be presented upon backend API accesses. This way any Approov cloud network accesses will be correlated with the need for network accesses anyway.
You should never cache a secure string in your own app code. Always make a call to fetch the value prior to using it in an API request that needs it. The Approov SDK automatically caches the values in a protected form and only performs a network request if a refresh is required. Moreover, the SDK performs additional fast checks on app integrity every time the secure string is fetched even if it is cached in memory.
Enabling Secure Strings
Secure strings are enabled by default for new Approov accounts.
If you have an Approov account created prior to version 3.2 it will not be enabled by default and any attempt to fetch them from the SDK will result in a DISABLED / disabled error. Enable the feature using:
approov secstrings -setEnabled
You will need an admin role and to provide confirmation to do this:
WARNING: this will have an immediate impact on your apps in production
ATTENTION: If you wish to continue then please type YES and return: YES
secure strings enablement updated
Once enabled it is possible to use app instance secure strings but there will be no predefined strings by default.
The feature can be disabled using:
approov secstrings -setDisabled
Again, this will need an admin role and for confirmation to be provided. Note that this will discard all predefined secure string values.
Managing Predefined Secure Strings
You can add predefined secure string values using the Approov CLI. Imagine you wish to protect a secret-value. This might be some sort of API key or client secret that needs to be presented on an API call, but you don't wish to hard code the value in your app. To access the value it needs to be assigned a key. This is secret-name in this case. Issue the following command:
approov secstrings -addKey secret-name -predefinedValue secret-value
You will need an admin role and to provide confirmation to do this.
WARNING: this will have an immediate impact on your apps in production
ATTENTION: If you wish to continue then please type YES and return: YES
secure strings updated
The secret-value will then be available to any running apps that look it up using the key name secret-name and have passed the Approov attestation checks.
You may define up to 16 different secure string values. The key names are limited to a maximum of 64 characters. There is no limit on the length of individual values. However, the complete size of all key names and values is limited to approximately 8KB.
You can retrieve the status of the secure strings at any point with:
approov secstrings -get
This shows if the feature is enabled or not, and provides a list of all of the key and value pairings if it is enabled:
secure strings feature is enabled
1 predefined string:
secret-name: secret-value
Finally, the predefined secure string with the key secret-name can be removed as follows:
approov secstrings -removeKey secret-name
You will need an admin role and to provide confirmation to do this:
WARNING: this will have an immediate impact on your apps in production
ATTENTION: If you wish to continue then please type YES and return: YES
secure strings updated
Any apps that look up this value will start to receive an UNKNOWN_KEY / unknownKey error status from the SDK, which will result in an empty value from a Quickstart integration.
Fetching Predefined Secure Strings
The Mobile App Quickstarts provide a method to fetch a secure string, given a parameter of the key. In this case you should provide an empty newDef since you only wish to lookup predefined values.
The integrations allow secrets in headers or URL query parameters to be automatically inserted. Typically this means that an existing secret in the app just needs to be changed to a placeholder value and the actual secret can be inserted, for valid app instances, just in time as the network request is being made. Follow the instructions for your particular quickstart.
If the app fails its integrity check then a REJECTED / rejected status is provided and the secure string is not available (this differs from the behavior of Approov tokens, which would provide an incorrectly signed JWT in this case). Your app implementation will need to handle this gracefully and provide feedback to the user. This may include a retry option, but most rejection causes will likely persist. You should consider the use of Attestation Response Code or Rejection Reasons in order to provide feedback. An Attestation Response Code will provide an alphanumeric code that can only be decoded if it is given to your app support team (and they are setup to decode it). Rejection Reasons will provide a direct indication of the cause of the problem.
The fetch might also fail due to network connectivity issues, in which case you should provide a user initiated retry option.
Secure strings are only supported in version 3.0.0 and later SDKs.
App Instance Secure Strings
Predefined Secure Strings have their values set using the Approov CLI and those same values are accessible to all of your registered Apps. It is also possible to securely store strings for the app instance. This uses the same SDK methods as reading, but uses the newDef parameter for the call to define a new value for the given key name.
For example, suppose your app has received an accessTokenValue and you wish to store that securely in persistent storage for your app. In this case you might store it under the key value access_token. The newDef value should be assigned to accessTokenValue. Executing the fetchSecureString will then store this value in a protected and encrypted form on the device.
Note that the store only succeeds if the operation returns the value back again. If there is an error of any sort then the value will not have been saved and your code will need to deal with such a situation.
If you store a value with the same key name as one used for a predefined secure string then subsequent accesses to that value will retrieve the local value. That is, the predefined value will be unavailable until the local value is removed.
The Approov SDK stores the string in SharedPreferences, using MODE_PRIVATE for Android and NSUserDefaults for iOS. This persists the secure strings between app restarts. The secure string values are stored in an encrypted form to protect them at rest from analysis tools. The decryption key is only provided to the app from the Approov cloud service if the attestation is passed. Note that the string values are never transmitted to or stored by the Approov cloud service itself, which only manages the encryption key and not the data.
If you try and retrieve a secure string for a value that is not defined at all then you will get an empty value (such as null) returned. Normally this shouldn't happen because your program logic will ensure that the value is defined before it is used. But be aware that it is possible for the user to manually clear the properties persisted for an app and in that case this status will be returned, so you will need to deal with it gracefully.