Skip to content

Commit

Permalink
Replace safetyNey to Play Integrity (#2371)
Browse files Browse the repository at this point in the history
* Replace SafetyNet to Play Integrity

* Show MASVS v1 IDs in the tests tables (#2522)

* add masvs v1 IDs to tests table

* Refactor column_titles and masvs_v1_id formatting in populate_dynamic_pages.py

* Apply suggestions from code review

* fix broken link

---------

Co-authored-by: Edilson Galvão <edilsongalvao@bemol.com.br>
Co-authored-by: Carlos Holguera <perezholguera@gmail.com>
  • Loading branch information
3 people committed Feb 7, 2024
1 parent 6bfdaf8 commit e4b9b5d
Showing 1 changed file with 53 additions and 41 deletions.
94 changes: 53 additions & 41 deletions Document/0x05j-Testing-Resiliency-Against-Reverse-Engineering.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,60 +30,72 @@ In the following section, we list some common root detection methods you'll enco

Root detection can also be implemented through libraries such as [RootBeer](https://github.com/scottyab/rootbeer "RootBeer").

#### SafetyNet
#### Google Play Integrity

SafetyNet is an Android API that provides a set of services and creates profiles of devices according to software and hardware information. This profile is then compared to a list of accepted device models that have passed Android compatibility testing. Google [recommends](https://developers.google.com/android/reference/com/google/android/gms/safetynet/SafetyNet "SafetyNet Documentation") using the feature as "an additional in-depth defense signal as part of an anti-abuse system".
Google has launched the [Google Play Integrity API](https://developer.android.com/google/play/integrity/overview "Google Play Integrity API") to improve the security and integrity of apps and games on Android starting with Android 4.4 (level 19). The previous official API, [SafetyNet](https://developer.android.com/training/safetynet), did not cover all the security needs that Google wanted for the platform, so Play Integrity was developed with the basic functions of the previous API and integrated additional features. This change aims to protect users from dangerous and fraudulent interactions.

How exactly SafetyNet works is not well documented and may change at any time. When you call this API, SafetyNet downloads a binary package containing the device validation code provided from Google, and the code is then dynamically executed via reflection. An [analysis by John Kozyrakis](https://koz.io/inside-safetynet/ "SafetyNet: Google's tamper detection for Android") showed that SafetyNet also attempts to detect whether the device is rooted, but exactly how that's determined is unclear.
**Google Play Integrity offers the following safeguards:**

To use the API, an app may call the `SafetyNetApi.attest` method (which returns a JWS message with the _Attestation Result_) and then check the following fields:
- Verification of genuine Android device: It verifies that the application is running on a legitimate Android device.
- User license validation: It indicates whether the application or game was installed or purchased through the Google Play Store.
- Unmodified binary verification: It determines whether the application is interacting with the original binary recognized by Google Play.

- `ctsProfileMatch`: If 'true', the device profile matches one of Google's listed devices.
- `basicIntegrity`: If 'true', the device running the app likely hasn't been tampered with.
- `nonces`: To match the response to its request.
- `timestampMs`: To check how much time has passed since you made the request and you got the response. A delayed response may suggest suspicious activity.
- `apkPackageName`, `apkCertificateDigestSha256`, `apkDigestSha256`: Provide information about the APK, which is used to verify the identity of the calling app. These parameters are absent if the API cannot reliably determine the APK information.
The API provides four macro categories of information to help the security team make a decision. These categories include:

The following is a sample attestation result:
1. **Request Details**: In this section, details are obtained about the app package that requested the integrity check, including its format (e.g., com.example.myapp), a base64-encoded ID provided by the developer to link the request with the integrity certificate, and the execution time of the request in milliseconds.

```json
{
"nonce": "R2Rra24fVm5xa2Mg",
"timestampMs": 9860437986543,
"apkPackageName": "com.package.name.of.requesting.app",
"apkCertificateDigestSha256": ["base64 encoded, SHA-256 hash of the
certificate used to sign requesting app"],
"apkDigestSha256": "base64 encoded, SHA-256 hash of the app's APK",
"ctsProfileMatch": true,
"basicIntegrity": true,
}
```
2. **App Integrity**: This section provides information about the integrity of the app, including the result of the verification (denominated verdict), which indicates whether the app's installation source is trusted (via Play Store) or unknown/suspicious. If the installation source is considered secure, the app version will also be displayed.

3. **Account Details**: This category provides information about the app licensing status. The result can be `LICENSED`, indicating that the user purchased or installed the app on the Google Play Store; `UNLICENSED`, meaning that the user does not own the app or did not acquire it through the Google Play Store; or `UNEVALUATED`, which means that the licensing details could not be evaluated because a necessary requirement is missing, that is, the device may not be trustworthy enough or the installed app version is not recognized by the Google Play Store.

##### ctsProfileMatch Vs basicIntegrity
4. **Device Integrity**: This section presents information that verifies the authenticity of the Android environment in which the app is running.

The SafetyNet Attestation API initially provided a single value called `basicIntegrity` to help developers determine the integrity of a device. As the API evolved, Google 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.
- `MEETS_DEVICE_INTEGRITY`: The app is on an Android device with Google Play Services, passing system integrity checks and compatibility requirements.
- `MEETS_BASIC_INTEGRITY`: The app is on a device that may not be approved to run Google Play Services but passes basic integrity checks, possibly due to an unrecognized Android version, unlocked bootloader, or lack of manufacturer certification.
- `MEETS_STRONG_INTEGRITY`: The app is on a device with Google Play Services, ensuring robust system integrity with features like hardware-protected boot.
- `MEETS_VIRTUAL_INTEGRITY`: The app runs in an emulator with Google Play Services, passing system integrity checks and meeting Android compatibility requirements.

In broad terms, `basicIntegrity` gives you a signal about the general integrity of the device and its API. Many Rooted devices fail `basicIntegrity`, as do emulators, virtual devices, and devices with signs of tampering, such as API hooks.
**API Errors:**

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:
The API can return local errors such as `APP_NOT_INSTALLED` and `APP_UID_MISMATCH`, which can indicate a fraud attempt or attack. In addition, outdated Google Play Services or Play Store can also cause errors, and it is important to check these situations to ensure proper integrity verification functionality and to ensure the environment is not intentionally set up for an attack. You can find more details on the [official page](https://developer.android.com/google/play/integrity/error-codes).

- Devices that fail `basicIntegrity`
- Devices with an unlocked bootloader
- Devices with a custom system image (custom ROM)
- Devices for which the manufacturer 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)
**Best practices:**

##### Recommendations when using `SafetyNetApi.attest`
1. Use Play Integrity as part of a broader security strategy. Complement it with additional security measures such as input data validation, user authentication, and anti-fraud protection.
2. Minimize queries to the Play Protect API to reduce device resource impact. For example, employ the API only for essential device integrity verifications.

- Create a large (16 bytes or longer) random number on your server using a cryptographically-secure random function so that a malicious user can not reuse a successful attestation result in place of an unsuccessful result
- Trust APK information (`apkPackageName`, `apkCertificateDigestSha256` and `apkDigestSha256`) only if the value of `ctsProfileMatch` is true.
- The entire JWS response should be sent to your server, using a secure connection, for verification. It isn't recommended to perform the verification directly in the app because, in that case, there is no guarantee that the verification logic itself hasn't been modified.
- The `verify` method only validates that the JWS message was signed by SafetyNet. It doesn't verify that the payload of the verdict matches your expectations. As useful as this service may seem, it is designed for test purposes only, and it has very strict usage quotas of 10,000 requests per day, per project which will not be increased upon request. Hence, you should refer [SafetyNet Verification Samples](https://github.com/googlesamples/android-play-safetynet/tree/master/server/java/src/main/java "Google SafetyNet Sample") and implement the digital signature verification logic on your server in a way that it doesn't depend on Google's servers.
- 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. It's recommended to plan a strategy to use the least amount of attestations required to satisfy the use case.
- To prevent inadvertently reaching your `SafetyNetApi.attest` 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](https://support.google.com/googleplay/android-developer/contact/safetynetqr "quota request") 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.
3. Include a `NONCE` with integrity verification requests. This random value, generated by the app or server, helps the verification server confirm that responses match the original requests without third-party tampering.

Follow this [checklist](https://developer.android.com/training/safetynet/attestation-checklist "attestation checklist") to ensure that you've completed each of the steps needed to integrate the `SafetyNetApi.attest` API into the app.
**Limitations:**
The default daily limit for Google Play Services Integrity Verification API requests is 10,000 requests per day. Applications needing more must contact Google to request an increased limit.

**Example Request:**

```json
{
   "requestDetails": {
     "requestPackageName": "com.example.your.package",
     "timestampMillis": "1666025823025",
     "nonce": "kx7QEkGebwQfBalJ4...Xwjhak7o3uHDDQTTqI"
   },
   "appIntegrity": {
     "appRecognitionVerdict": "UNRECOGNIZED_VERSION",
     "packageName": "com.example.your.package",
     "certificateSha256Digest": [
       "vNsB0...ww1U"
     ],
     "versionCode": "1"
   },
   "deviceIntegrity": {
     "deviceRecognitionVerdict": [
       "MEETS_DEVICE_INTEGRITY"
     ]
   },
   "accountDetails": {
     "appLicensingVerdict": "UNEVALUATED"
   }
 }
```

#### Programmatic Detection

Expand Down Expand Up @@ -207,7 +219,7 @@ for (int i = 1; ; i = 0)
}
```

Missing Google Over-The-Air (OTA) certificates is another sign of a custom ROM: on stock Android builds, [OTA updates Google's public certificates](https://blog.netspi.com/android-root-detection-techniques/ "Android Root Detection Techniques").
Missing Google Over-The-Air (OTA) certificates is another sign of a custom ROM: on stock Android builds, [OTA updates Google's public certificates](https://www.netspi.com/blog/technical/mobile-application-penetration-testing/android-root-detection-techniques/ "Android Root Detection Techniques").

### Anti-Debugging

Expand Down

0 comments on commit e4b9b5d

Please sign in to comment.