Skip to main content

Managing Dynamic Pinning

It is essential that all channels used to communicate Approov tokens, or secure strings, are protected against Man-in-the-Middle (MitM) interception. This means that the app should only be willing to establish a TLS connection where the presented certificates are both valid and are as expected. Public key certificate pinning is used to achieve this, as detailed in Dynamic Pinning. By default, the managed trust roots facility is used which effectively limits the set of root certificates that may be used, even if the device is modified. Explicit public key pinning options are also available to determine more specific pin requirements. Protection will be provided automatically if you have used one of our Mobile App Quickstarts.

Managed Trust Roots

By default the managed trust roots facility is used instead of explicit pins. This handles all situations, even when the backend API is not managed by the same organization as the mobile app. In this case the public key pin of the presented certificate could be changed at any point. Moreover, the issuing certificate authority and therefore the root certificate could also be changed at the time of renewal or indeed at any time.

To deal with this, Approov provides a set of trusted roots with the same set of certificate authorities typically trusted by the iOS and Android system trust stores. The set of trusted roots is managed by Approov and is dynamically updated as required. If any individual root certificate is revoked then Approov removes it from the trusted set and the update will be picked up by all apps on their next attestation. Approov monitors the iOS and Android system trust stores for changes and updates the Approov managed trust roots appropriately.

In the app, the trusted roots set is enforced in addition to the trust store on the device itself. A root certificate has to be present in both sets for a connection to be established. Without this protection a Man-in-the-Middle (MitM) proxy can simply install a self signed certificate into the system trust store of a device (either on an emulator or a rooted/jailbroken device) and then intercept traffic. With managed trust roots enabled, this style of attack is prevented because the self signed root certificate cannot be added to the Approov managed trust roots and therefore any connection attempts with the MitM proxy certificate will be rejected. Only connections to a certificate in a chain to a legitimate root authority will be accepted.

Controlling Managed Trust Roots

For new Approov accounts, Managed trust roots are enabled by default. If you have an Approov account where it is not enabled use:

approov pin -setManagedTrustRoots on

An admin role and confirmation is required:

WARNING: updating the managed trust roots policy will have an immediate impact on your apps in production
ATTENTION: If you wish to continue then please type YES and return: YES
managed trust roots policy was set successfully
warning

Managed trust roots require some changes to the pinning management logic for Approov quickstarts. If you are a pre-existing Approov customer where managed trust roots are not enabled by default, you must only enable this if using a quickstart designed for a 3.0.0 SDK or later.

Managed trust roots can be disabled using the above command with off.

warning

Disabling managed trust roots while some domains have no specific pin configuration will leave those domains relying solely on the system trust store and therefore potentially exposed to MitM attacks.

It is possible to get the current status of managed trust roots using:

approov pin -getManagedTrustRoots

Adding a Leaf Pin

Although managed trust roots are used by default, you can choose to provide an explicit set of pins for an API domain that has been added. This will ensure that communication can only occur if one of the specific set of pins provided is present. You should only do this if you have control or visibility of the backend API being pinned to, and therefore will have some notice before the pin might change so you can update your Approov configuration beforehand.

You can add the leaf pin for a specific API domain using the following command:

approov pin -add your.domain -addLeafPin matching

You will be asked for confirmation:

WARNING: updating the pins will have an immediate impact on your apps in production
ATTENTION: If you wish to continue then please type YES and return: YES
pin gPXaRc4yVQHyqlts3sZFECBDlSmRCuyVFk8f2UIukJk= added to API your.domain

The pin is extracted from the leaf certificate presented by the domain’s server. When a leaf pin is collected with the matching parameter then the pin is calculated 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:

domain your.domain 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).

In this case a different pin matching approach can be used by changing the parameter to -addLeafPin 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.
tip

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. Connections are made whenever a new token is required (default 5 minutes). To avoid pinning failures when deploying a new certificate, you should add the new certificate pin and wait for the token lifetime to elapse (5 minutes) before deploying the new certificate on your servers. Once the certificate is deployed and in use by your servers or load balancer, you can remove the old pin for the domain (this will trigger another configuration update). Using this approach, you can deploy a certificate with a new pin with no downtime for your apps.

Adding a Leaf Pin with a Port

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

approov pin -api your.domain -addLeafPin local -port 8000
info

Pin sets are recorded per domain and the same set is used to check each connection to that domain, no matter which port is used. If your apps make connections to multiple ports on the same domain then please make sure that the pin set includes a valid pin for each of the different certificates used by the accessed ports on that domain.

Listing the Pins

You can always see the pins configured for any domain as follows:

approov pin -api your.domain -list

This shows the set of pins that have been set for the domain. This will be shown as unpinned if no pins have been set, but managed trust roots will still be in place if these are enabled (as is the default).

Adding an Explicit Pin

It is also possible to add an arbitrary specific 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 your.domain -add Q62DnTGJsy1h+ude8HB5ZjKy0Vhg2pvTzjplWSD3hkk=

Note that you need an admin role to modify the pins and you will be asked for confirmation:

WARNING: updating the pins will have an immediate impact on your apps in production
ATTENTION: If you wish to continue then please type YES and return: YES
pin Q62DnTGJsy1h+ude8HB5ZjKy0Vhg2pvTzjplWSD3hkk= added to API domain your.domain

Removing an Explicit Pin

Specific pins can be removed as follows:

approov pin -api your.domain -remove Q62DnTGJsy1h+ude8HB5ZjKy0Vhg2pvTzjplWSD3hkk=

This also requires confirmation:

WARNING: updating the pins will have an immediate impact on your apps in production
ATTENTION: If you wish to continue then please type YES and return: YES
removed pin Q62DnTGJsy1h+ude8HB5ZjKy0Vhg2pvTzjplWSD3hkk= from API domain your.domain
warning

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

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 or root certificate within the chain presented by a domain. A command is provided to extract this information:

approov pin -api approov.io -getCertChainPins

This shows the full chain of certificates:

pin gPXaRc4yVQHyqlts3sZFECBDlSmRCuyVFk8f2UIukJk=, expiry 2024-06-20, CN=approov.net
pin 18tkPyr2nckv4fgo0dhAkaUtJ2hu2831xlO2SKhq8dg=, expiry 2030-08-23, CN=Amazon RSA 2048 M02,O=Amazon,C=US
pin ++MBgDH5WGvL9Bcn5Be30cRcL0f5O+NyoXuWtQdX1aI=, expiry 2038-01-17, CN=Amazon Root CA 1,O=Amazon,C=US

For this example we use our website domain approov.io which is hosted by 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 may change frequently or at unpredictable times. (Note, in the specific case of AWS, they suggest you add a pin for all their published root certificates so that it doesn't matter which root is used when updating your certificate.)

Once the pin is obtained use Adding an Explicit Pin to add it to the required domain.

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.

info

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 your-cert.crt

Which will output something like:

pin jZetC3373f9dmwxg5YE9TCZzl4MYvp0eYTiEsbcTU34=, expiry 2022-05-10, CN=your.domain

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.

Once the pin is obtained use Adding an Explicit Pin to add it to the required domain.

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.

First, you need to get 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

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==

Which will output something like:

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. See Adding an Explicit Pin to add one of the pins shown.

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.

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 for 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

This outputs the result of the check as follows:

your.domain:
no pins defined
shapes.approov.io:
certificate chain:
dqP5GOntRqZST5GfBj8NGpr1GMUTeKZG5g6+Q5mZFYM= CN=shapes.demo.approov.io
jQJTbIh0grw0/1TkHSumWb+Fs0Ggogr621gT3PvPKG0= CN=R3,O=Let's Encrypt,C=US
pins:
dqP5GOntRqZST5GfBj8NGpr1GMUTeKZG5g6+Q5mZFYM=
matched pin dqP5GOntRqZST5GfBj8NGpr1GMUTeKZG5g6+Q5mZFYM=

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 then that is considered an error.

If pins are defined for a particular API domain then the certificate chain observed is shown, along with the list of pins that are defined for the domain. If there is a matching pin then that is also listed.

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.

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.

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 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 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.

warning

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 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 pinning mechanism has been compromised in 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 pin -setPinningTestURL https://your.domain:443

You will be asked for confirmation:

WARNING: updating the pinning test URL will have an immediate impact on your apps in production
ATTENTION: If you wish to continue then please type 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 pin -getPinningTestURL

Finally you can remove the URL at any point using:

approov pin -removePinningTestURL

Again, you will be asked for confirmation:

WARNING: updating the pinning test URL will have an immediate impact on your apps in production
ATTENTION: If you wish to continue then please type YES and return: YES
pinning test URL was updated successfully

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

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:

{
"your.domain": {
"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 your.domain 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 none.
  • allowWeb: This is an optional boolean flag that is only shown if true. It indicates that the API domain may have web protection Approov tokens fetched for it.
  • algorithm: Provides the type of signing or encryption algorithm for the API domain (or empty for none).
  • 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 explicit pins for the domain. Empty indicates that no pinning is applied, although connections may still be protected with managed trust roots.
  • monitorPort: If continuous 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.

{
"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

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:

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
ATTENTION: If you wish to continue then please type YES and return: YES
APIs set successfully

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.

tip

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.

warning

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.

warning

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