Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Resolve security questions around ZIP 321 and zcash: handler registration by malicious apps #60

Open
daira opened this issue Apr 12, 2024 · 30 comments
Labels
I-SECURITY Problems and improvements related to security. P-urgent Urgent priority
Milestone

Comments

@daira
Copy link
Contributor

daira commented Apr 12, 2024

No description provided.

@daira daira added the I-SECURITY Problems and improvements related to security. label Apr 12, 2024
@daira daira added this to the Zashi 1.1 milestone Apr 12, 2024
@daira
Copy link
Contributor Author

daira commented Apr 12, 2024

@true-jared true-jared added the P-urgent Urgent priority label Apr 12, 2024
@skyl
Copy link

skyl commented May 4, 2024

User must willfully select the malicious app to handle the intent? Doesn't seem like a realistic or practical attack from my understanding.

@skyl
Copy link

skyl commented May 4, 2024

Wallet-specific URIs wouldn't be useful or convenient. Seems like a bad idea.

@daira
Copy link
Contributor Author

daira commented Jun 6, 2024

No, it's not correct that a user must willfully select the malicious app. Here's a write-up that covers that misperception.

Background on potential attacks

URI handler interception

It is not possible, on either Android or iOS, for a wallet app to reliably ensure that only it (or only other genuine wallet apps) can register as handlers for a given URI scheme.

On iOS, the behaviour is particularly unhelpful: one of the apps that registers for that scheme will be selected, but there is no user input, no reliable or documented specification of how the selection is made, and nothing in the UI that would indicate to the user that other apps are registered for that scheme.

On Android, the user is presented with a list of apps that have registered for the scheme, but there is no way to prevent a malicious app from having a confusingly similar name and icon to the correct app.

Activating the wrong app can have both privacy implications (the intercepting app gets the URI, and can potentially use the address, amount, etc. for social engineering attacks or in chain analysis), and integrity implications (the intercepting app could pass a modified URI, perhaps paying to the attacker's own address, to the real wallet app that has the user's spending keys).

Clipboard interception

The clipboard is not secure on either iOS or Android. Arbitrary apps can intercept and modify the clipboard contents, and there is no practical way to prevent this.

The visibility of this attack to the user depends on the platform version and the permissions granted to the malicious app. Modifying the clipboard contents (without reading them) never notifies the user on iOS or Android. There was also no visibility to the user of an app reading clipboard contents before Android 12 or iOS 14. After those versions, a system notification is supposed to be displayed (e.g. "${short app name} pasted from your clipboard" for Android). However, certain permissions allow this notification to be overdrawn on Android.

Proposed solution

It is safe to parse zcash: URIs from a wallet's own QR code scanner. We also propose to register a zcash: handler that only displays a message and then exits.

The message should convey to the user that they need to manually open the wallet they intend to use, and scan zcash: QR codes using that wallet's scanning UI. It would also be good to be able to allow the user to paste in a URI, but unfortunately we can't because of clipboard interception.

Hypothesis: this will be more convincing if the security problems are explained to the user.

Proposed wording of the warning screen

You have scanned or followed a zcash: link representing a payment request.

On $OS there is no way to ensure that this way of using zcash: links will reach your intended wallet app.

If a malicious app were installed on your device, it could:

  • gain information about the payment, which could then be used in social engineering attacks or to link this use of Zcash with other transactions;
  • modify the link and then pass it on to a real wallet app, which could result in you sending money to the wrong address.

These attack possibilities apply when scanning a QR code, following a link, or copying and pasting a link from the clipboard.

To maintain your privacy and security, please instead manually open the Zcash wallet app that you intend to pay with, and use its scanning feature to scan QR codes. If you do this in future then it will be faster as well as more secure: you won't need to go through this screen again, and you will be safer from any malicious apps.

For Zashi the scanner is [brief description of how to get to it].

We can't automatically open Zashi for you because this screen could also be faked by a malicious app. Thanks for reading, and sorry for the inconvenience.

         [Close this message]

@daira
Copy link
Contributor Author

daira commented Jun 21, 2024

@LukasKorba and @true-jared raised the issue that according to iOS documentation and previous versions of Apple's Human Interface Guidelines (although I cannot find it in the current guidelines), an app should not quit programmatically. Instead it's intended that users tap the Home control to go back to the home screen (there is no equivalent of the Back control on Android).

It is definitely possible to adapt the behaviour to both follow the human interface guidelines and meet the security requirements. The warning screen tells the user to tap the Home button and go into the app again. The app detects the resulting UIApplication.willResignActiveNotification event and navigates to the app's main screen (while it is in the background), so that when it is foregrounded again it will be on the right screen. This teaches the user the safe way to act on a payment request QR code.

@nuttycom
Copy link
Contributor

It is definitely possible to adapt the behaviour to both follow the human interface guidelines and meet the security requirements. The warning screen tells the user to tap the Home button and go into the app again. The app detects the resulting UIApplication.willResignActiveNotification event and navigates to the app's main screen. This teaches the user the safe way to act on a payment request QR code.

If the app instead just takes the user into the scanning UI in Zashi, how is that any worse? A malicious app that emulates this behavior can't gain any additional capabilities that it didn't already have. I think that the UX cost of what you're proposing here is too high for too little gain, vs. educating the user and then taking them to the camera to re-scan.

@daira
Copy link
Contributor Author

daira commented Jun 21, 2024

That UI doesn't solve the "URI leaks information to malicious app" problem. You have to train the user not to use the system scanner for things that might be payment links in order to solve that. If they get directly to the place they need to be by doing the wrong thing, then they'll continue to do the wrong thing.

Don't think of just the specific case in which the link got intercepted, think of every future case with that user.

@true-jared
Copy link

I think we can close this one, right, guys? @daira @nuttycom

@nuttycom nuttycom closed this as completed Nov 7, 2024
@nuttycom
Copy link
Contributor

nuttycom commented Nov 8, 2024

To summarize what was decided:

  • When scanning a ZIP 321 URI using the system scanner, the user will be redirected to a page in the application that directs them to re-scan using the Zashi scanner.

@Tomas-M
Copy link

Tomas-M commented Feb 5, 2025

Unfortunately, this is not a solution for me.

First of all, on both Android and iOS, camera access is indeed governed by strict permissions, sandboxing, and hardware-level protections. However, if an attacker gains elevated privileges—whether by exploiting a vulnerability or by rooting/jailbreaking the device—they may intercept the camera’s data flow. This could involve installing a kernel-level driver or modifying system libraries so that the raw camera stream is intercepted or altered before reaching the intended application.

Additionally, instructing users to scan a QR code through Zashi’s internal scanner does not resolve the issue. When a user browses a website on their mobile device and then attempts to pay via Zashi, they cannot scan a QR code that appears on the same screen. While a user might take a screenshot of the QR code and then scan it from their photo gallery, a malicious app could modify even the screenshot. Thus, the problem persists in the current Zashi implementation.

Furthermore the payment link does not necessarily have to be encoded exclusively as a QR code; it can also be presented as a clickable HTML anchor tag (e.g., Pay with Zcash).

Rejecting the registration of the “zcash:” URL scheme does not provide a security benefit. In fact, allowing multiple apps to register the URL scheme may be preferable, as it presents the user with a choice - alerting them to a potential anomaly - rather than having Zashi completely opt out and potentially enabling a malicious app to always intercept the URL! This approach preserves user experience and interoperability while also offering a visible indication that something unusual may be occurring, at least on Android.

In summary, rejecting URL scheme registration outright sacrifices crucial user experience without delivering a proportional security benefit. Allowing multiple apps to register the URL scheme is better than opting out.

One proposed solution is to implement a ZIP specification that defines how a payment URL is transformed—via a cryptographic hash function—into a short control hash. This hash would be displayed on the website generating the payment link alongside the zcash: payment link. When the user initiates a payment by clicking a zcash: link, it would open in Zashi, and the user can verify that the control hash shown on the website matches the hash generated from the payment URL. This additional verification step would help ensure that the URL has not been most likely tampered with by a malicious intermediary, thereby alerting the user to any discrepancies in a clear and transparent manner.

Please reopen this ticket

@nuttycom
Copy link
Contributor

nuttycom commented Feb 5, 2025

Rejecting the registration of the “zcash:” URL scheme does not provide a security benefit. In fact, allowing multiple apps to register the URL scheme may be preferable, as it presents the user with a choice - alerting them to a potential anomaly - rather than having Zashi completely opt out and potentially enabling a malicious app to always intercept the URL! This approach preserves user experience and interoperability while also offering a visible indication that something unusual may be occurring, at least on Android.

@Tomas-M the problem here is with iOS: on iOS, if multiple handlers are registered for the zcash: URL scheme, an application will be chosen at random to open the URI. It's a horrible situation; you're quite correct that ideally it would open the system app chooser dialog, but that's not the situation.

I like your idea of adding a convention around verifying a control hash, but unfortunately since the control hash is out-of-band it just provides extra assurance for cautious users (who should be verifying the proposed transaction anyway) and doesn't actually increase the security of the protocol.

@Tomas-M
Copy link

Tomas-M commented Feb 5, 2025

@nuttycom having a random application to open the URI is better than having it GUARANTEED that malicious app opens it every time just because Zashi refused to register the URL scheme.

@nuttycom
Copy link
Contributor

nuttycom commented Feb 5, 2025

@nuttycom having a random application to open the URI is better than having it GUARANTEED that malicious app opens it every time just because Zashi refused to register the URL scheme.

@Tomas-M Zashi does register the URL scheme; when selected by the system it displays an informational page to the user to encourage them to scan Zcash payment URIs directly using their preferred wallet app, and then allows them to open the Zashi scanner.

@Tomas-M
Copy link

Tomas-M commented Feb 5, 2025

Nowadays, people use mobile phones more than ever. Even for browsing websites. If user uses his mobile phone, and the QR code for payment is displayed on the screen of the mobile phone, how should he scan it? There is no way. He has to make a screenshot and we have the same problem like before because the screenshot can be changed by malicious app. There must be a way to solve this. Furthermore Zashi should support opening of the Zashi app by clicking a link (or even clicking on the qr code itself) if user is on the same device and cannot scan it. Clicking <a href=zcash:....> does not solve this, so we need to find different solution.

So, people, heads up! There is a solution for this problem!
Read carefully.

Domain links, also known as universal links (iOS) or app links (Android), allow a specific website URL to directly open an associated app. Here’s how it works and why it’s an ideal solution for ensuring that Zcash payments always open in the correct application (Zashi):

Secure Association:

The domain owner (in this case, the Zcash team) hosts an association file on a dedicated domain (e.g., pay.z.cash). For iOS, this is an apple-app-site-association file, and for Android, an assetlinks.json file. These files explicitly list the app identifiers (such as Zashi’s bundle ID) that are authorized to handle links from this domain.

User Interaction:

When a user clicks a payment link formatted as a standard HTTPS URL (for example, https://pay.z.cash/?amount=...&address=...&memo=...), the operating system checks the association file on pay.z.cash. If Zashi is installed and registered, the OS launches it directly to process the payment. If not, the link simply opens in a web browser, providing a fallback - the website can display the QR code with zcash: scheme, and also links to download Zashi application. Most users will never reach the website, only those who do not have the app installed.

Enhanced Security and User Experience:

Because the association is verified by the operating system, only the app specified by the domain (Zashi) can claim the link. This prevents malicious apps from intercepting or hijacking the payment URL. Moreover, the user benefits from a seamless experience—clicking a link immediately opens Zashi without ambiguity or the need to choose from multiple options.

App Side Configuration:

The app (Zashi) must declare support for specific domains by adding the associated domain (e.g., pay.z.cash) to its manifest or entitlements file. This registration tells the operating system that the app is authorized to handle links from that domain, ensuring that when users tap a payment link, the OS directs them to Zashi.

Domain Side Configuration:

The domain owner must host an association file on the domain’s server (an apple-app-site-association file for iOS or an assetlinks.json file for Android) that lists the approved app identifiers. This file validates that only the registered app can claim the links, securely binding the payment URL to the correct application.

Example

For example alza.cz (which is something like an Amazon but in Czech Republic) opens its own application instead web URLs, because they have the support in their app, and they have this file online http://alza.cz/.well-known/assetlinks.json

Summary

By switching from a custom URL scheme like zcash: to a domain-based URL (e.g., https://pay.z.cash/?amount=...), you ensure that the payment link is securely bound to the correct app. This approach leverages established OS-level mechanisms to maintain both security and a user-friendly experience, ensuring that all payment requests are handled reliably by Zashi.

@nuttycom
Copy link
Contributor

nuttycom commented Feb 5, 2025

By switching from a custom URL scheme like zcash: to a domain-based URL (e.g., https://pay.z.cash/?amount=...), you ensure that the payment link is securely bound to the correct app. This approach leverages established OS-level mechanisms to maintain both security and a user-friendly experience, ensuring that all payment requests are handled reliably by Zashi.

We absolutely considered this option, on a number of occasions. The problem is that using an applink means that a single entity (the entity in control of that domain) becomes a point of failure for the entire ecosystem that adopts the use of that domain. Individual app developers could choose to register their own domains for trusted applinks, but then you end up with not being able to have a single standard for the whole ecosystem.

If there were a single entity that held that domain, you'd always run the risk that someone scanning such a link would, in resolving it, end up exposing the relationship between their phone's IP address and their interest in that particular payment request. This is an unacceptable level of centralization and information leakage. We considered registering a domain and ensuring that it could never be resolved, but that just results in an ongoing risk to the ecosystem. For example, a government could sieze control of the domain and use it to collect IP addresses of Zcash users.

@Tomas-M
Copy link

Tomas-M commented Feb 5, 2025

I understand that adopting a domain-based solution might introduce an additional point of failure. Fair enough. However, taking a step back, I believe that the existing zcash: URL scheme is just fine. Rejecting proper URL scheme registration undermines essential user experience while failing to provide a corresponding security benefit. Ultimately, many users will copy and paste receiver addresses via the clipboard, and it is impossible to protect everyone. Moreover, it is not our responsibility to safeguard users who knowingly or even unintentionally install potentially malicious applications on their devices.

My motivation for addressing this issue stems from the anticipated wide adoption of Zcash payments. I am developing software that relies entirely on Zcash transactions, and when it goes live, it may introduce hundreds of thousands of new users to the ecosystem. Requiring these users to take a screenshot of a QR code and then manually open the Zashi app to scan that image is both impractical and inefficient. Moreover, it is relatively simple for an app to modify screenshots of QR codes to alter receiver addresses, meaning that the practical implications of such a design decision could be far more severe than anticipated. In light of these concerns, I am seriously considering forking the existing wallet apps to create a better solution for my users.

@nuttycom
Copy link
Contributor

nuttycom commented Feb 5, 2025

@Tomas-M I feel like we're talking at cross-purposes here. I recommend the following experiment to you:

  • Go to https://zecpages.com and use the "post builder" functionality to create a ZIP 321 QR code.
  • Open your phone that has Zashi installed and scan that QR code (with the system scanner.)

There is no requirement to screenshot the QR code.

@nuttycom
Copy link
Contributor

nuttycom commented Feb 5, 2025

Note, I just noticed there's a bug (at least on iOS) such that the flow only works properly if the app is already active in the background; something related to the biometric auth seems to interfere with the flow from the system scanner if the app is fully unloaded.

@skyl
Copy link

skyl commented Feb 5, 2025

@Tomas-M I feel like we're talking at cross-purposes here. I recommend the following experiment to you:

  • Go to https://zecpages.com and use the "post builder" functionality to create a ZIP 321 QR code.
  • Open your phone that has Zashi installed and scan that QR code (with the system scanner.)

There is no requirement to screenshot the QR code.

I want to click the link on the same phone that has the wallet, not have 2 screens. I don't know about iOS and this "select random" business - sounds like something that should be escalated with Apple. The way Ywallet and Zingo handle it on Android (and Mac Desktop and Linux) is fine. If iOS has a terrible bug where any app can register for zcash: and the app is chosen at random, Zashi shouldn't workaround this by degrading the user experience. I find it hard to believe this is how it works on iOS. If it's true then I'd say warn the users that iOS has this flaw. zcash: app selection works great on Android. If some malicious app registers zcash:, gets installed on the user device, and then is randomly selected when the user clicks on a zcash: link .. then ... what is that app going to do? I guess I don't buy the threat model in practice anyways.

Go here, click the donate button, and then click the zcash: link ... walk me through what bad can happen like I'm 5?

@Tomas-M
Copy link

Tomas-M commented Feb 5, 2025

@nuttycom How should I do it?
My workflow is this:

  • I have my phone only, no PC
  • I go to a website where I want to pay with zcash (I browse that website on my phone)
  • The website prints a QR code for me to scan to pay, this QR code is displayed in my browser in my phone, I have no PC.
  • I have no possible way of scanning this QR code with Zashi app, since that is also on my phone. I have no PC
  • I need to printscreen the QR code, then open Zashi app, and click scan QR code, then click image to choose photo from Gallery

For users who use mobile phones, no PC, it would be beneficial to allow them to click some <a href=zcash:.....> link, which would open the Zashi app in their phone, avoiding QR codes at all. Or the <a href link can be on the QR code element, so the user could just click the QR code to "visit the link" (open Zashi with prefilled send form). Do you understand what I am talking about? :)

@skyl
Copy link

skyl commented Feb 5, 2025

For users who use mobile phones, no PC, it would be beneficial to allow them to click some <a href=zcash:.....> link, which would open the Zashi app in their phone, avoiding QR codes at all. Or the link can be on the QR code, so the user could just click the QR code to "visit the link". Do you understand what I am talking about? :)

Indeed, that's essentially what you find on a f2z profile

@nuttycom
Copy link
Contributor

nuttycom commented Feb 5, 2025

I want to click the link on the same phone that has the wallet, not have 2 screens.

Ah, okay, I understand the problem you're referring to better now. Sorry that I was slow on the uptake there.

I don't know about iOS and this "select random" business - sounds like something that should be escalated with Apple. The way Ywallet and Zingo handle it on Android (and Mac Desktop and Linux) is fine. If iOS has a terrible bug where any app can register for zcash: and the app is chosen at random, Zashi shouldn't workaround this by degrading the user experience. I find it hard to believe this is how it works on iOS. If it's true then I'd say warn the users that iOS has this flaw. zcash: app selection works great on Android.

I know that it's hard to believe that iOS has such a disastrous issue, but yes, that's actually the issue; see the note here: https://developer.apple.com/documentation/xcode/defining-a-custom-url-scheme-for-your-app#Register-your-URL-scheme and also the answers to https://stackoverflow.com/questions/13130442/multiple-apps-with-the-same-url-scheme-ios

It's been brought up to Apple by probably thousands of developers and they flatly refuse to fix it.

@skyl
Copy link

skyl commented Feb 5, 2025

It's been brought up to Apple by probably thousands of developers and they flatly refuse to fix it.

Well, that's their problem IMHO. I'm still trying to put my black hat on and figure out how I can profit off of this but I'm not seeing anything great I can do with a malicious app.

@Tomas-M
Copy link

Tomas-M commented Feb 5, 2025

It's been brought up to Apple by probably thousands of developers and they flatly refuse to fix it.

In this case, if users have problems with malicious software stealing their money, blame apple, that's just it.

@Tomas-M
Copy link

Tomas-M commented Feb 5, 2025

It's been brought up to Apple by probably thousands of developers and they flatly refuse to fix it.

Well, that's their problem IMHO. I'm still trying to put my black hat on and figure out how I can profit off of this but I'm not seeing anything great I can do with a malicious app.

I imagine (only imagine) that they think that the malicious app could modify receiver address, and then open zashi with prefilled send form, so the user would unintentionally send money to that modified address. But I have no idea if this is a real threat

@nuttycom
Copy link
Contributor

nuttycom commented Feb 5, 2025

It's been brought up to Apple by probably thousands of developers and they flatly refuse to fix it.

Well, that's their problem IMHO. I'm still trying to put my black hat on and figure out how I can profit off of this but I'm not seeing anything great I can do with a malicious app.

Basically, the malicious app can steal the information about what the user is trying to buy (and also deanonymize users who are trying to buy from the zcash:-supporting site.) If using Zcash is illegal in someone's country, such an app can be used to identify that the user is breaking (or trying to break) the law.

@nuttycom
Copy link
Contributor

nuttycom commented Feb 5, 2025

Reopening due to #60 (comment)

@nuttycom nuttycom reopened this Feb 5, 2025
@daira
Copy link
Contributor Author

daira commented Feb 6, 2025

However, if an attacker gains elevated privileges—whether by exploiting a vulnerability or by rooting/jailbreaking the device—they may intercept the camera’s data flow.

That's not the problem we were trying to fix — because it's unfixable.

It is still important to prevent attacks by malicious apps in the case where those apps are not able to obtain elevated privileges.

It's been brought up to Apple by probably thousands of developers and they flatly refuse to fix it.

In this case, if users have problems with malicious software stealing their money, blame apple, that's just it.

That's not acceptable; we have to build on the platforms as they are, not as we would want them to be. As @nuttycom pointed out, this is documented and intended behaviour of the platform.

@Tomas-M
Copy link

Tomas-M commented Feb 6, 2025

We keep going around in circles with the idea that a fraudulent app could register zcash: URL scheme and can cause nasty things, and for that reason, you don't want to register URL schema for the Zashi wallet. But we probably forgot something.

If zcash: url scheme is not registered by zashi, this does not in any way prevent other applications (legit ones or malicious ones) from registering the zcash: scheme themselves, possibly leaking users payment data, or doing any other nasty things. User will scan zcash: qr code or click zcash: link anyway. Malicious app will display nice dialog saying:

Thank you for scanning the QR code or clicking the payment link, for your convenience, receiver address has been copied to clipboard. Paste it in your wallet for easier payment.

Voila, user will follow the onscreen instructions and paste the address. If you register the URL schema, there is always greater than zero chance that Zashi will handle the link instead of the malicious app, compared to zero chance if you do not register the URL schema at all.

So, your decision to reject registering the url scheme helps nobody.
If the user has malicious app, it will cause problems regardless of your decision.
I strongly propose to stop supporting users with malicious apps, it is their problem, not yours.

@true-jared
Copy link

true-jared commented Feb 6, 2025

@Tomas-M You have stirred a big team discussion, we appreciate all your input and advocacy for usability. 😎 We have some additional ideas for potential improvements! Please let us evaluate this internally, and let you know the outcome.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
I-SECURITY Problems and improvements related to security. P-urgent Urgent priority
Projects
None yet
Development

No branches or pull requests

5 participants