13 November 2017
Posted by Oscar Rodriguez, Partner Developer Advocate
[Note: This blog was amended in March 2018 to include our latest recommendations regarding app integrity verification, in May 2019 to amend the quota increase request form link, and in July 2022 to announce the deprecation of this API.]
[Note: The SafetyNet Attestation API is now deprecated. This blog post remains for reference, but new and existing developers should use the Play Integrity API instead.]
The SafetyNet Attestation API helps you assess the security and compatibility of the Android environments in which your apps run. Since it was introduced in March 2015, many developers have successfully integrated it into their Android apps to make more informed decisions based on the integrity and compatibility of the devices running their apps.
Throughout the years, the SafetyNet Attestation API has evolved, and its adoption has steadily increased. However, as with any security/anti-abuse related API, there are many common pitfalls that may lead developers into developing unstable systems, or worse, into a false sense of security.
In this post, we provide a list of the most common mistakes we have seen developers make when integrating the SafetyNet Attestation API.
Just like many other Google APIs, the SafetyNet Attestation API requires an API key in order to run. Furthermore, the SafetyNet Attestation API has a per-key usage quota. Although you can get this quota increased, you need to provide your API key to do so.
Getting an API key is easy and free of charge. There is no reason not to get an API key, so if you haven't already, get an API key now.
The SafetyNet Attestation API has evolved throughout its history, and with it,
there have been some interface changes. Most recently, with the release of
Google Play services 11.0.0, we revamped the entire SafetyNet API to offer an
interface that is easier and more streamlined to use: the new API uses SafetyNetClient
instead of SafetyNetApi
,
which is now deprecated, so make sure you update your implementation to use the
latest version of the API.
Most devices should have the latest version of Google Play services installed, but if a device doesn't have Google Play services installed, or doesn't have it up to date, using the SafetyNet Attestation API may lead to the app becoming unresponsive or crashing. You can prevent this by checking the installed version of Google Play services before using the API.
The SafetyNet Attestation API lets you set a nonce to uniquely and globally identify each call to the API. Use this feature to prevent a malicious user from reusing a successful attestation result in place of an unsuccessful result (also known as a Replay Attack).
One good way to create a nonce is to create a large (16 bytes or longer) random number on your server using a cryptographically-secure random function. The SafetyNet attestation response includes the nonce you set, so make sure you verify that the returned nonce matches the one you included in the request you made.
SafetyNet can provide useful signals about the state of the device in which your app is running. However, if the logic that acts on these signals is only implemented and enforced directly on the device, an attacker could be able to modify your app and bypass any checks you perform.
To prevent this situation, you should run any logic that verifies the attestation result and enforces any actions based on them on a server that you control and trust.
In order to simplify development and testing of the SafetyNet Attestation API, Google offers an online verification service that checks the digital signature of a SafetyNet Attestation result using a simple HTTPS request.
As useful as this service may seem, it is designed for test purposes only, and it has very strict usage quotas that will not be increased upon request. Instead, you should implement the digital signature verification logic on your server in a way that it doesn't depend on Google's servers. Most JWT libraries offer signature verification functionality, and we have code samples that show how to perform this verification in Java and C#. We plan to provide samples for more languages in the future.
The SafetyNet Attestation API is most widely known for its integrity and
compatibility checks, whose results are returned in ctsProfileMatch
and basicIntegrity
. Although these two values are indeed very
useful, you should check the other values in the response, as they contain
important information as well.
Use nonce
to match a response to its request,
as explained above, and use timestampMs
to check how much time has passed since you made the
request and you got the response. A delayed response that arrives several hours
or days after the request may suggest suspicious activity.
Use apkPackageName
to check the name of the APK that made the
attestation request, and match apkDigestSha256
and
apkCertificateDigestSha256
to those from your app's signed APK in
Google Play, to get a signal about the integrity of the installed app.
You can also use apkDigestSha256
to check the hash value of the APK installed on the user device. Be aware, however, that distribution channels, such as Google Play may include additional metadata into the APK, so apkDigestSha256
might differ from the hash value of the APK that you uploaded to your distribution channel. In most cases, using apkPackageName
and apkCertificateDigestSha256
should be sufficient signals for verifying the integrity of the APK.
Remember that the trustworthiness of the response as a whole is tied to the
results of ctsProfileMatch
and basicIntegrity
. It is
not unthinkable for a compromised device that fails basicIntegrity
to have forged the rest of the values in the response.
ctsProfileMatch
and basicIntegrity
The SafetyNet Attestation API initially provided a single value called
basicIntegrity
to help developers determine the integrity of a
device. As the API evolved, we introduced a new, stricter check whose results
appear in a value called ctsProfileMatch
, which allows developers
to more finely evaluate the devices on which their app is running.
In broad terms, basicIntegrity
gives you a signal about the general
integrity of the device and its API. Rooted devices fail
basicIntegrity
, as do emulators, virtual devices, and devices with
signs of tampering, such as API hooks.
On the other hand, ctsProfileMatch
gives you a much stricter signal
about the compatibility of the device. Only unmodified devices that
have been certified by Google can pass ctsProfileMatch
. Devices
that will fail ctsProfileMatch
include the following:
basicIntegrity
The SafetyNet Attestation API gives you a snapshot of the state of a device at the moment when the attestation request was made. A successful attestation doesn't necessarily mean that the device would have passed attestation in the past, or that it will in the future.
Because an attestation is just a spot check, you should plan a sensible strategy for choosing when to make attestation requests. You may choose to require successful attestations before users make in-app purchases, after a certain number of days have passed since the last successful attestation, each time your app is launched, after every reboot, or any other strategy that makes sense for your app.
Keep in mind that an attestation request is computationally expensive, consumes battery and bandwidth, and uses your quota. We recommend you plan a strategy to use the least amount of attestations required to satisfy your use case.
It may be tempting to think that the SafetyNet Attestation API provides all the necessary signals for protecting an app against abusers, and use it as the only signal for building an anti-abuse system.
The SafetyNet Attestation API can only give signals about the state of a device, not the intent of a user, which is what an anti-abuse system should be designed to detect. Therefore, you might want to consider including other signals, such as access logs and behavioral patterns, to more accurately detect abusive users, and consider not blocking users solely on a failed attestation. Furthermore, there are many other conditions that cause an attestation to fail, such as network connection problems, quota issues, and other transient problems.
In other words, not all users who fail attestation are necessarily abusers, and not all abusers will necessarily fail attestation. By blocking users solely on their attestation results, you might be missing abusive users that don't fail attestations. Furthermore, you might also be blocking legitimate, loyal customers who fail attestations for reasons other than abuse.
As mentioned before, the SafetyNet Attestation API is rate limited, and there is a default quota of 10,000 requests per day for each API key. Although this quota might be enough for most development, testing, and initial app launches, your app might reach the default limit as it increases in popularity.
To prevent inadvertently reaching your quota and getting attestation errors, you should build a system that monitors your usage of the API and warns you well before you reach your quota so you can get it increased. You should also be prepared to handle attestation failures because of an exceeded quota and avoid blocking all your users in this situation.
If you are close to reaching your quota, or expect a short-term spike that may lead you to exceed your quota, you can submit this form to request short or long-term increases to the quota for your API key. This process, as well as the additional quota, is free of charge.