Skip to content
This repository has been archived by the owner on May 16, 2023. It is now read-only.

[Data Donation] Android App integrity check alternatives #356

Closed
thomasaugsten opened this issue Feb 1, 2021 · 20 comments
Closed

[Data Donation] Android App integrity check alternatives #356

thomasaugsten opened this issue Feb 1, 2021 · 20 comments
Assignees
Labels
enhancement New feature or request mirrored-to-jira This item is also tracked internally in JIRA

Comments

@thomasaugsten
Copy link
Member

thomasaugsten commented Feb 1, 2021

To prevent wrong information via the data donation we check via SafetyNet the app digest and the certificate chain of the JWS signature on the data donation server. This is not a root check.

This is needed for the opt-in feature when the user wants to share the information when for example receive an exposure notification (data donation). The will exclude user user the micro-G implementation or the CTG app.

We should discuss if there any alternatives to check the integrity of the app without identify the user.
And is there a way to add microG or CTG in the app integrity check


Internal Tracking ID: EXPOSUREAPP-4754

@fynngodau
Copy link
Contributor

fynngodau commented Feb 1, 2021

I'm looking forward to the docs you mentioned in corona-warn-app/cwa-app-android#2242 (comment), as I'm still unsure about the overall design on the new features. In specific, to what extend "survey" and "data donation" are two separate features, which does what and when, when SafteyNet is required, and so on, which I'm hoping the docs will clarify.

@thomasaugsten
Copy link
Member Author

We will have data donation of facts like how many red and green risk cards are displayed.
The survey link will displayed for user with red risk card they can answer some general question what they thing about this red risk card.
Because of decentralized approach we cannot check the red risk cards on the server we can only check the app integrity.
For both feature we need SafteyNet to check the app integrity to be sure the user really received a red risk card.

@fynngodau
Copy link
Contributor

fynngodau commented Feb 1, 2021

Are you going to link the data from the data donation of a specific device together, e.g. to track for how long a device displays a high-risk warning (just an example, not saying that this couldn’t be tracked otherwise)?

If not, are you technically capable of linking individual transmissons by a specific device using the SafteyNet attestations? I don’t know what those look like, whether they are "anonymous" towards the verifier or just pseudonymous.

My approach would probably have been to enforce a delay at the scale of days or weeks between installation of the app / enabling the feature and being able to send data, though I don’t see a way to do that without allowing some link between some of the queries. Maybe an approach where multiple users are grouped together to share one identity towards the server could be thought out to address that.

This would mean that an attacker would have to plan their attack in advance, and I believe this would already discourage people enough from disturbing the system “just because they can”. Additionally, you could monitor for extraordinary amounts of ‘registrations’.

A second thing I’m wondering about: to my understanding, SafteyNet can attest different levels of ‘integrity’. Which level of integrity are you going to require, what constraints does this imply and how is this supposed to prevent abuse?

@thomasaugsten
Copy link
Member Author

thomasaugsten commented Feb 1, 2021

The data donation is completely anonymous and no device specific information are linked to the data. It is also not possible to see when different submissions came from the same device.

SafetyNet attestation is completely anonymous we only save a part of the nonce in a different table for 1 day to prevent replay attacks
SafetyNet Example
We have a 24h delay after installation to prevent spamming through reinstallation. Then a daily submission when new data is available

At the moment we plan to use only the app digest to check integrity of our app.

@tomjschwanke
Copy link

Googles Page about SafetyNet says

Caution: You should trust the APK information only if the value of ctsProfileMatch is true.

If I understood that correctly, couldn't an attacker with evil intent hook into the SafetyNet Attestation using root and spoof the signature value(extracted from the real app)?

@fynngodau
Copy link
Contributor

@thomasaugsten Thanks for the link.

@tomjschwanke I'm assuming that they are going to require ctsProfileMatch since this page says that, but maybe this is not decided yet, considering that the SafteyNet PR adds tests for various different modes of required attestation. And yes, that's a way that it could work otherwise (under the assumption that the attestation always works correctly as documented, which it of course doesn't): you could modify your system to output an incorrect hash of the package, if that's what the server is checking for.

@tomjschwanke
Copy link

@fynngodau I was thinking more of spoofing the correct apkDigestSha256. It can easily be calculated and then you hook into SafetyNet to forge a response that would be accepted by the server. I'm not sure if the apkCertificateDigestSha256 is more secure in that regard, since it's the

base64 encoded SHA256 hash of the signing certificates used

I'm not sure how easy it would be to forge that.
Verifiying ctsProfileMatch would definitively be more secure (it can still be bypassed but probably not for very long).
I can't tell if ctsProfileMatch will be required

@mar-v-in
Copy link

mar-v-in commented Feb 3, 2021

When using SafetyNet, you should be aware that this alone is not sufficient to effectively block abusers. Typically, you'd want to implement additional measures like rate limiting, plausibility checks and so on.

For example, Pokemon Go is well known to use SafetyNet, yet they also spot abusers by detecting if users travel large distances in short time.

Check section 9 of this Google blog post:

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.

Regarding ctsProfileMatch: I use a home-brewed custom rom and such can modify the reported digests at will, yet using microG and some additional hacks I still can produce a ctsProfileMatch = true. Basically, with SafetyNet you are lifting the bar of your attackers from bored trolls that can send arbitrary HTTP requests to bored trolls that can follow a YouTube tutorial on how to get Pokemon Go running on rooted devices. It's better than nothing, but certainly not a sufficient abuse protection.

@tomjschwanke
Copy link

Currently SafetyNet still accepts BASIC attestation, I can imagine however that in the near future they will only accept HARDWARE_BACKED attestation which have to be signed by the devices TEE. Not sure how they'll handle older devices.

@thomasaugsten
Copy link
Member Author

The ctsProfileMatch is easy to fake and also on old genuine devices can happens this property is false.
Regarding apkDigestSha256 is a public information but there is no simple way to spoof it.
There is no easy way to fake the signature and certificate chain of the JWS.
The nonce include also a hash of the payload to check if the analytic payload matches the JWS

@mar-v-in
Copy link

mar-v-in commented Feb 4, 2021

This is a SafetyNet JWS token with valid signature from Google and payload as follows.

eyJhbGciOiJSUzI1NiIsIng1YyI6WyJNSUlGbERDQ0JIeWdBd0lCQWdJUkFQUWdpNWZxN3EvQkFnQUFBQUNFUGRZd0RRWUpLb1pJaHZjTkFRRUxCUUF3UWpFTE1Ba0dBMVVFQmhNQ1ZWTXhIakFjQmdOVkJBb1RGVWR2YjJkc1pTQlVjblZ6ZENCVFpYSjJhV05sY3pFVE1CRUdBMVVFQXhNS1IxUlRJRU5CSURGUE1UQWVGdzB5TURFeU1UVXhNREUxTlRGYUZ3MHlNVEEyTVRNeE1ERTFOVEJhTUd3eEN6QUpCZ05WQkFZVEFsVlRNUk13RVFZRFZRUUlFd3BEWVd4cFptOXlibWxoTVJZd0ZBWURWUVFIRXcxTmIzVnVkR0ZwYmlCV2FXVjNNUk13RVFZRFZRUUtFd3BIYjI5bmJHVWdURXhETVJzd0dRWURWUVFERXhKaGRIUmxjM1F1WVc1a2NtOXBaQzVqYjIwd2dnRWlNQTBHQ1NxR1NJYjNEUUVCQVFVQUE0SUJEd0F3Z2dFS0FvSUJBUUNwYmx2WFhpejJrRGkrNFBKL1o1ZGRpdG9FckhyTkZwWWJteGdEM3BxQXA1U2xQeEVwUXNPdzRnWTZtWkJpelUxWWJrdXZxZFkwMUd3QVBOUk5MeEgrVHJPbk1TOGQ1U2FGbXcrMWd1V3Q5a0twajVveUN4dmtkSXBWQmp5bmg3amxQcTZCYndFblpOazBvb01hTW5yRW5Ebmpxb2N0Z095T1hFdmFTWlhwaktSaWRKL2k0dFhGWXU2SUtOakQrQkN1VXVNdGNKRjNvRHpFYVpQdlpnNzU4NFpmSnZHaHI3dlYvMy9VVjdlQlNQZXFBSkxNYWtkRFgyMlE1ekxKMnNUaUs2blhxZGhpUlVma1ZycDdRTFFxTVZCVzd4US82ZzZYdXYxZ2VyYTRjbktzS1hxY1dxUllCUWx4Ujltemw4UmVyQ2FGRXJZK2Q0bnV0anJ6TlNYN0FnTUJBQUdqZ2dKWk1JSUNWVEFPQmdOVkhROEJBZjhFQkFNQ0JhQXdFd1lEVlIwbEJBd3dDZ1lJS3dZQkJRVUhBd0V3REFZRFZSMFRBUUgvQkFJd0FEQWRCZ05WSFE0RUZnUVV1RGxJUktOSW5hdkZkYzF0ZkllZCt1WTE4M1F3SHdZRFZSMGpCQmd3Rm9BVW1OSDRiaERyejV2c1lKOFlrQnVnNjMwSi9Tc3daQVlJS3dZQkJRVUhBUUVFV0RCV01DY0dDQ3NHQVFVRkJ6QUJoaHRvZEhSd09pOHZiMk56Y0M1d2Eya3VaMjl2Wnk5bmRITXhiekV3S3dZSUt3WUJCUVVITUFLR0gyaDBkSEE2THk5d2Eya3VaMjl2Wnk5bmMzSXlMMGRVVXpGUE1TNWpjblF3SFFZRFZSMFJCQll3RklJU1lYUjBaWE4wTG1GdVpISnZhV1F1WTI5dE1DRUdBMVVkSUFRYU1CZ3dDQVlHWjRFTUFRSUNNQXdHQ2lzR0FRUUIxbmtDQlFNd0x3WURWUjBmQkNnd0pqQWtvQ0tnSUlZZWFIUjBjRG92TDJOeWJDNXdhMmt1WjI5dlp5OUhWRk14VHpFdVkzSnNNSUlCQlFZS0t3WUJCQUhXZVFJRUFnU0I5Z1NCOHdEeEFIY0E3c0NWN28xeVpBK1M0OE81RzhjU28ybHFDWHRMYWhvVU9PWkhzc3Z0eGZrQUFBRjJaaDBhc1FBQUJBTUFTREJHQWlFQW9wL05BemFZV1BWWDFDNld2amF3QkY3Mm5xTjRwNjdLVTdhRzBhd0U4K1FDSVFEVFV6VjJndDYwdmhaZElyb2pLZ1VCb25HY1ZOd1hvdFluREY1V01tRXpBd0IyQVBaY2xDL1JkekFpRkZRWUNEQ1VWbzdqVFJNWk03L2ZEQzhnQzh4TzhXVGpBQUFCZG1ZZEdqNEFBQVFEQUVjd1JRSWdDT1l1ZmVKR0xSMzU5UGpYemI4c0NmWVdtaGlQeHZEZk9zWFlHMzN2d2l3Q0lRQ3lOMHRydHlyTFJHbjNVdUY5SG1KRUNHNEVDTmhLU1c0aUw1VG54NXhBRlRBTkJna3Foa2lHOXcwQkFRc0ZBQU9DQVFFQVgwMnFKV1RsTlowekZXa3NBMjJsY3A1bEVEV0lZdEc4cXp4cWhOVmZsNlFxUzRFcjFkaFFFbnc3eSt4cDhOTVpSWXZRZVRFeVRGL1FBTnZCYUtUUmlXaWZJOTZBZkJKcDJVUFZMcVpUK3Jwc216UGM1TXpwaERBVW1NRlV3U0JEODAxUkVoUjgvTW5CdFg2aXEwcjc2WlVheVN3dVZ5WGNUWmQwK3cwRkdTbWZVZG1lTUY2Uno5QW9kVXFFMWNEa3NudmI0QzNwUnZOcm9mbXBsSUF2WGdnL3RmR1VWRXVuS3lTMjBnczN4WDROMklRZDRxNlUzRk1oaWN2ejI2T2xrK3krM01xOVNSTkdiZk82dmhib2hEc09nYnNMdzY3aDN3ZlFON2lzYmhKcDRIR2hsdm5mKysxL1ZvdmdmYythUGFVUklCdWFSR1NVK2hEWkxrbXV3Zz09IiwiTUlJRVNqQ0NBektnQXdJQkFnSU5BZU8wbXFHTmlxbUJKV2xRdURBTkJna3Foa2lHOXcwQkFRc0ZBREJNTVNBd0hnWURWUVFMRXhkSGJHOWlZV3hUYVdkdUlGSnZiM1FnUTBFZ0xTQlNNakVUTUJFR0ExVUVDaE1LUjJ4dlltRnNVMmxuYmpFVE1CRUdBMVVFQXhNS1IyeHZZbUZzVTJsbmJqQWVGdzB4TnpBMk1UVXdNREF3TkRKYUZ3MHlNVEV5TVRVd01EQXdOREphTUVJeEN6QUpCZ05WQkFZVEFsVlRNUjR3SEFZRFZRUUtFeFZIYjI5bmJHVWdWSEoxYzNRZ1UyVnlkbWxqWlhNeEV6QVJCZ05WQkFNVENrZFVVeUJEUVNBeFR6RXdnZ0VpTUEwR0NTcUdTSWIzRFFFQkFRVUFBNElCRHdBd2dnRUtBb0lCQVFEUUdNOUYxSXZOMDV6a1FPOSt0TjFwSVJ2Snp6eU9USFc1RHpFWmhEMmVQQ252VUEwUWsyOEZnSUNmS3FDOUVrc0M0VDJmV0JZay9qQ2ZDM1IzVlpNZFMvZE40WktDRVBaUnJBekRzaUtVRHpScm1CQko1d3VkZ3puZElNWWNMZS9SR0dGbDV5T0RJS2dqRXYvU0pIL1VMK2RFYWx0TjExQm1zSytlUW1NRisrQWN4R05ocjU5cU0vOWlsNzFJMmROOEZHZmNkZHd1YWVqNGJYaHAwTGNRQmJqeE1jSTdKUDBhTTNUNEkrRHNheG1LRnNianphVE5DOXV6cEZsZ09JZzdyUjI1eG95blV4djh2Tm1rcTd6ZFBHSFhreFdZN29HOWorSmtSeUJBQms3WHJKZm91Y0JaRXFGSkpTUGs3WEEwTEtXMFkzejVvejJEMGMxdEpLd0hBZ01CQUFHamdnRXpNSUlCTHpBT0JnTlZIUThCQWY4RUJBTUNBWVl3SFFZRFZSMGxCQll3RkFZSUt3WUJCUVVIQXdFR0NDc0dBUVVGQndNQ01CSUdBMVVkRXdFQi93UUlNQVlCQWY4Q0FRQXdIUVlEVlIwT0JCWUVGSmpSK0c0UTY4K2I3R0NmR0pBYm9PdDlDZjByTUI4R0ExVWRJd1FZTUJhQUZKdmlCMWRuSEI3QWFnYmVXYlNhTGQvY0dZWXVNRFVHQ0NzR0FRVUZCd0VCQkNrd0p6QWxCZ2dyQmdFRkJRY3dBWVlaYUhSMGNEb3ZMMjlqYzNBdWNHdHBMbWR2YjJjdlozTnlNakF5QmdOVkhSOEVLekFwTUNlZ0phQWpoaUZvZEhSd09pOHZZM0pzTG5CcmFTNW5iMjluTDJkemNqSXZaM055TWk1amNtd3dQd1lEVlIwZ0JEZ3dOakEwQmdabmdRd0JBZ0l3S2pBb0JnZ3JCZ0VGQlFjQ0FSWWNhSFIwY0hNNkx5OXdhMmt1WjI5dlp5OXlaWEJ2YzJsMGIzSjVMekFOQmdrcWhraUc5dzBCQVFzRkFBT0NBUUVBR29BK05ubjc4eTZwUmpkOVhsUVdOYTdIVGdpWi9yM1JOR2ttVW1ZSFBRcTZTY3RpOVBFYWp2d1JUMmlXVEhRcjAyZmVzcU9xQlkyRVRVd2daUStsbHRvTkZ2aHNPOXR2QkNPSWF6cHN3V0M5YUo5eGp1NHRXRFFIOE5WVTZZWlovWHRlRFNHVTlZekpxUGpZOHEzTUR4cnptcWVwQkNmNW84bXcvd0o0YTJHNnh6VXI2RmI2VDhNY0RPMjJQTFJMNnUzTTRUenMzQTJNMWo2YnlrSllpOHdXSVJkQXZLTFdadS9heEJWYnpZbXFtd2ttNXpMU0RXNW5JQUpiRUxDUUNad01INTZ0MkR2cW9meHM2QkJjQ0ZJWlVTcHh1Nng2dGQwVjdTdkpDQ29zaXJTbUlhdGovOWRTU1ZEUWliZXQ4cS83VUs0djRaVU44MGF0blp6MXlnPT0iXX0.eyJub25jZSI6IlUyRm1aWFI1VG1WMElHbHpJR3AxYzNRZ1lTQnphVzVwYm1jZ2IzSmhZMnhsTGc9PSIsInRpbWVzdGFtcE1zIjoxNjEyNDExMDMxOTgxLCJhcGtQYWNrYWdlTmFtZSI6ImRlLnJraS5jb3JvbmF3YXJuYXBwIiwiYXBrRGlnZXN0U2hhMjU2IjoiRjl6elZGOWRsY0o3aThNeW9RUllRMHo1OG9PTjBrSmVVNjE2M3RzZ1l2UT0iLCJjdHNQcm9maWxlTWF0Y2giOnRydWUsImFwa0NlcnRpZmljYXRlRGlnZXN0U2hhMjU2IjpbIkRkYXkrMTdkOXZZNVl0c25IdTErOVFUSGQ5bDNMVWhFY3F6d2VWT2U1ems9Il0sImJhc2ljSW50ZWdyaXR5Ijp0cnVlLCJldmFsdWF0aW9uVHlwZSI6IkJBU0lDIn0.JtYaxs4B7nuFncjLqMZ29Dwltj6yWTwr8Hmj1nWKbEHFksF5AE8zWxLZ6WbRBCsgWJrykTyQIYErG-ffFvbfTOZiH7JZyhCb5DgKeSPWc5S6UCw6JBhPp71C71lVjDGJQwDgDqYdfqoqGj2gupbLZCwFBP0J8qFaIbz9GenmJB--EBNp2_8Sv9NTr64csmCHSgvVzV5ain2BpuEM47FfIzVatCXQKnFuWE4ZsuPn0q5dJbty8-0gky1_DFZx3KhBDK7TNyNkaIBnqCI6gG1RwVUmyZ1in2f5rjq71KwLPyJvM7X8h-cjCZIq5n_axxsdObbwgmZV1IwOLshqqIajgg
{
  "nonce": "U2FmZXR5TmV0IGlzIGp1c3QgYSBzaW5pbmcgb3JhY2xlLg==",
  "timestampMs": 1612411031981,
  "apkPackageName": "de.rki.coronawarnapp",
  "apkDigestSha256": "F9zzVF9dlcJ7i8MyoQRYQ0z58oON0kJeU6163tsgYvQ=",
  "ctsProfileMatch": true,
  "apkCertificateDigestSha256": [
    "Dday+17d9vY5YtsnHu1+9QTHd9l3LUhEcqzweVOe5zk="
  ],
  "basicIntegrity": true,
  "evaluationType": "BASIC"
}

According to this data, the token was created from official Corona-Warn-App 1.11.0 (check and compare apkDigestSha256) which obviously should not be possible given that that version has no SafetyNet code at all. It also has ctsProfileMatch true.

No matter what any Google employee may tell you: SafetyNet is not and never was a sufficient abuse protection or integrity check. It is suitable as a rate limiter (if you require every request to carry a different nonce), however you could also implement rate limiting using other techniques and without needing to trust Google to have proper rate limiting.

@heinezen heinezen moved this from ToDo to In Progress in [CM] cwa-wishlist Feb 7, 2021
@heinezen heinezen moved this from In Progress to ToDo in [CM] cwa-wishlist Feb 7, 2021
@dsarkar dsarkar added the mirrored-to-jira This item is also tracked internally in JIRA label Feb 11, 2021
@cwa-bot cwa-bot bot moved this from ToDo to Mirrored to Jira in [CM] cwa-wishlist Feb 11, 2021
@dsarkar
Copy link
Member

dsarkar commented Feb 11, 2021

Internal Tracking ID: EXPOSUREAPP-4754

@fynngodau
Copy link
Contributor

For your information, we are prepearing to release CCTG 1.13 without PPA and survey features. We can of course enable them again once a solution without Google SafteyNet can be used.

@cwa-bot cwa-bot bot moved this from Mirrored to Jira to ToDo in [CM] cwa-wishlist Feb 27, 2021
@thomasaugsten
Copy link
Member Author

thomasaugsten commented Mar 5, 2021

The version 1.13 is now released an includes the PPA and survey feature
To submit or participate on the survey you only need a basic SafetyNet Attestation. The information basic or hardware based is attached to the ppa data and the survey. This allows every Android user to attend at this features and the RKI can filter out "basic" ppa and survey data at the analytics level if they see a reason to filter out this data.

@dsarkar dsarkar moved this from ToDo to Mirrored to Jira in [CM] cwa-wishlist Mar 5, 2021
@fynngodau
Copy link
Contributor

Since you are already differentiating between BASIC and HARDWARE_BACKED attestation, why don't you make SafteyNet attestation optional? In case you notice any abuse, you could filter it as needed. Attackers would know that attacks are pointless as the attestation level they sent their malicious data with would simply be filtered out, and would therefore have to try to attack the harder HARDWARE_BACKED attestation level.

@cwa-bot cwa-bot bot moved this from Mirrored to Jira to ToDo in [CM] cwa-wishlist Mar 5, 2021
@heinezen heinezen moved this from ToDo to Mirrored to Jira in [CM] cwa-wishlist Mar 18, 2021
@dylangerdaly
Copy link

@mar-v-in
I use a home-brewed custom rom and such can modify the reported digests at will, yet using microG and some additional hacks I still can produce a ctsProfileMatch = true.

Could you explain what you did to get this to pass?

Also see microg/GmsCore#1470 in order to pass the HARDWARE_BACKED attestation.

@cwa-bot cwa-bot bot moved this from Mirrored to Jira to ToDo in [CM] cwa-wishlist Oct 26, 2021
@mar-v-in
Copy link

@dylangerdaly
This can't be easily reproduced on other devices, nor is suitable for any productive use. It is almost exclusively useful for development/debugging purposes - except if you include malicious usages. As it is not my intention to support malicious activities, I won't publish this or explain publicly how it is done exactly. If you have any specific questions on this topic, you can mail me at microg at larma dot de.

@larswmh
Copy link
Member

larswmh commented Jun 14, 2022

Closing this issue as the related internal ticket is set to completed.

@larswmh larswmh closed this as completed Jun 14, 2022
@Ein-Tim
Copy link
Contributor

Ein-Tim commented Jun 14, 2022

@larswmh

What was the conclusion in the internal ticket?

@larswmh
Copy link
Member

larswmh commented Jun 14, 2022

@Ein-Tim

What was the conclusion in the internal ticket?

There is no explicit conclusion in the ticket, but fix version is set to 1.13.
Related PR: corona-warn-app/cwa-app-android#2242

See @thomasaugsten's comment from further above:

The version 1.13 is now released an includes the PPA and survey feature
To submit or participate on the survey you only need a basic SafetyNet Attestation. The information basic or hardware based is attached to the ppa data and the survey. This allows every Android user to attend at this features and the RKI can filter out "basic" ppa and survey data at the analytics level if they see a reason to filter out this data.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
enhancement New feature or request mirrored-to-jira This item is also tracked internally in JIRA
Projects
Development

No branches or pull requests

8 participants