Closed Bug 770666 Opened 12 years ago Closed 11 years ago

No good way to determine if a receipt verify URL is reasonable

Categories

(Marketplace Graveyard :: Payments/Refunds, defect, P2)

defect

Tracking

(Not tracked)

RESOLVED FIXED
2013-04-11

People

(Reporter: ianbicking, Assigned: ianbicking)

References

Details

(Whiteboard: p=)

Right now the basic flow for validating a receipt:

1. Decode the receipt
2. Make sure the receipt came from a trusted store
3. Get the verify URL of that receipt
4. Check if the receipt is valid by asking the verify URL at the store

An application can determine 2 by checking against a known list of trusted stores (which the app has to maintain itself and follows business relationships they've established with stores).  But an application cannot easily determine that the verify URL actually belongs to the store that the receipt claims to be from.

So a simple attack could be to create a receipt like this:

    {iss: "https://marketplace.mozilla.org", verify: "http://attacker.com/verify", ...}

Unless you check the signature on the receipt (which is relatively difficult to do, compared to simply asking the verify URL), you cannot simply tell that attacker.com is an invalid verify location.

Currently the marketplace also uses a different domain for receipt verification (receiptverifier.marketplace.mozilla.com perhaps?) so you can't test that there is an origin match between the issuer and the verifier.

The simplest proposal I have to fix this is simply to require that the verifier be located at the same origin as the issuer.  I don't believe it adds any strong operational burden for us to do so, but that might not be true for other stores.  (And if we make this requirement we should document it in the receipt spec.)

Checking the signature of the receipt is considerably more work, including lots of certificate handling, so I'd rather we not require that in order to do a secure verification of the receipt.
Summary: No good way to determine if the verify URL is reasonable → No good way to determine if a receipt verify URL is reasonable
(In reply to Ian Bicking (:ianb) from comment #0)
> The simplest proposal I have to fix this is simply to require that the
> verifier be located at the same origin as the issuer. 

btw, browser ID solves this by letting a domain delegate authority to another domain. For example, if you try to log in as ianb@mozilla.com then browser ID connects to https://mozilla.com/.well-known/vep (if it exists) and there could be something in there that delegates identity checking to https://browserid.org


I don't see why iss comes into play here though when we're not talking about validating receipt signatures. Can't an attacker just make a receipt like this and install it on his machine:

    {iss: "http://myverifier.ru", verify: "http://myverifier.ru/verify", ...}

http://myverifier.ru/verify <-- always works

Is a better solution just to distribute all the right libraries to validate the receipt signature? Pretty soon we'll be able to do it directly in JS when DOMCrypt lands http://www.w3.org/2012/webcrypto/

disclaimer: I'm not familiar with the details of verifying the receipt signature + certs
It would be reasonable if we looked for, as an example, https://marketplace.mozilla.com/.well-known/receipt-verifier – which indicated who it is willing to delegate to for receipt verification.  Or, if we do same-origin verifiers this would offer a future path for relaxing that restriction.

I expect applications to include a whitelist of what origins they accept receipts from (and I don't see any other way to establish who has a business relationship with the application).  This handles the issue with "iss" simply being an invalid store.  But keeping a second whitelist of verification URLs seems more error-prone (and is not, for instance, documented for the Marketplace).
Agreed. So having a .well-known lookup would allow us to use the app manifest to solve this. If the manifest says 

installs_allowed_from = ['http://store1.org', 'http://store2.org'] 

then we could use the http://store1.org/.well-known/receipt-verifier to deduce trusted verify URLs per app manifest.

But yeah same-origin verifiers might be an easier first step.
+1 for same-origin verification
Seems easy enough. I filed bug 770746. Do we need to keep this one open or should we dupe it?
Bug 770746 will do for IT changes, should file a bug for the libraries to enforce this.
We also need to make doc changes.
Ian: can you file the follow up bugs and close this one? Thanks.
(In reply to Wil Clouser [:clouserw] from comment #8)
> Ian: can you file the follow up bugs and close this one? Thanks.

bug 770746 is related.  Ian: is there more to do here?
Once Bug 770746 lands we should change libraries; I think that would be good enough.
Depends on: 770746
Assignee: nobody → amckay
Priority: -- → P2
Version: 1.0 → 1.2
We've got the verifier on a subdomain of the issuer domain. That's a slight change to comment 0 where we allow a verification on the domain or sub-domain of the issuer.

Could we add this to the receipt verifier library please?
Assignee: amckay → ianb
To summarize: the patch we'd like to add to the receipt verifier JS lib is to only honor the verifier URL if it is a subdomain or exact match of the origin URL domain that installed the app. 

This will help prevent malicious users from installing fake receipts to fool the app server into using the app for free.
Whiteboard: p=
What is the status of this bug?
Flags: needinfo?(ianb)
We'd like to get a patch in for this because it will greatly enhance the security of the receiptverifier lib. See comment #12
I added support for requireSameOrigin to receiptverifier.js: https://github.com/mozilla/receiptverifier/commit/5ca96d9038cb74a7b0650eaeb9c2c7ab8552b2fa

It's currently off by default.  I don't really know if anyone is using the library, or how they are using it, so I'm not sure if turning this on by default could effect anyone.
Flags: needinfo?(ianb)
Thanks Ian, does it cope with subdomains as well as per comment 12?
Err... no, it's a straight origin check.  I suppose I could do subdomains, as a subdomain si probably harmless in this case.
This is fantastic, thanks Ian. We do need it to support subdomains since that's how the marketplace verifier is set up. 

Also, what's the harm in turning on this check by default? There is no one aside from the Firefox Marketplace issuing receipts yet so defaulting to true should be harmless.
https://github.com/mozilla/receiptverifier/commit/632bd0420d385e7db915b68c903fe20ec60f4e28

Now it's doing a subdomain check instead of an origin check, and it's always on (no option).
Woot, thanks.
Status: NEW → RESOLVED
Closed: 11 years ago
Resolution: --- → FIXED
Target Milestone: --- → 2013-04-11
You need to log in before you can comment on or make changes to this bug.