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.
1. Not getting an API key
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.
2. Not using the latest version of the API
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
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.
3. Using nonces incorrectly
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.
4. Not checking the results on your server
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.
5. Using the test attestation verification service for production
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.
6. Not checking the nonce, timestamp, APK name, and hashes
The SafetyNet Attestation API is most widely known for its integrity and
compatibility checks, whose results are returned in
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.
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.
apkPackageName to check the name of the APK that made the
attestation request, and match
apkCertificateDigestSha256 to those from your app's signed APK in
Google Play, to get a signal about the integrity of the installed app.
Remember that the trustworthiness of the response as a whole is tied to the
basicIntegrity. It is
not unthinkable for a compromised device that fails
to have forged the rest of the values in the response.
7. Not understanding the differences between
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
that will fail
ctsProfileMatch include the following:
- Devices that fail
- Devices with an unlocked bootloader
- Devices with a custom system image (custom ROM)
- Devices for which the manufactured didn't apply for, or pass, Google certification
- Devices with a system image built directly from the Android Open Source Program source files
- Devices with a system image distributed as part of a beta or developer preview program (including the Android Beta Program)
8. Not having a strategy for timing attestation checks
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.
9. Using the SafetyNet Attestation API results as the only signal to attack abuse
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.
10. Not monitoring and managing your usage quota
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.