Last Comment Bug 770666 - No good way to determine if a receipt verify URL is reasonable
: No good way to determine if a receipt verify URL is reasonable
Status: RESOLVED FIXED
p=
:
Product: Marketplace
Classification: Server Software
Component: Payments/Refunds (show other bugs)
: 1.2
: All All
: P2 normal (vote)
: 2013-04-11
Assigned To: Ian Bicking (:ianb)
:
:
Mentors:
Depends on: 770746
Blocks:
  Show dependency treegraph
 
Reported: 2012-07-03 14:05 PDT by Ian Bicking (:ianb)
Modified: 2013-04-12 10:55 PDT (History)
7 users (show)
See Also:
QA Whiteboard:
Iteration: ---
Points: ---


Attachments

Description Ian Bicking (:ianb) 2012-07-03 14:05:37 PDT
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.
Comment 1 Kumar McMillan [:kumar] (needinfo all the things) 2012-07-03 15:04:31 PDT
(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
Comment 2 Ian Bicking (:ianb) 2012-07-03 15:19:45 PDT
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).
Comment 3 Kumar McMillan [:kumar] (needinfo all the things) 2012-07-03 15:32:12 PDT
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.
Comment 4 Andy McKay [:andym] 2012-07-03 16:30:02 PDT
+1 for same-origin verification
Comment 5 Kumar McMillan [:kumar] (needinfo all the things) 2012-07-03 16:55:03 PDT
Seems easy enough. I filed bug 770746. Do we need to keep this one open or should we dupe it?
Comment 6 Andy McKay [:andym] 2012-07-04 09:18:25 PDT
Bug 770746 will do for IT changes, should file a bug for the libraries to enforce this.
Comment 7 Ian Bicking (:ianb) 2012-07-04 14:35:28 PDT
We also need to make doc changes.
Comment 8 Wil Clouser [:clouserw] 2012-07-05 10:37:31 PDT
Ian: can you file the follow up bugs and close this one? Thanks.
Comment 9 Wil Clouser [:clouserw] 2012-11-05 16:15:36 PST
(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?
Comment 10 Ian Bicking (:ianb) 2012-11-05 19:11:39 PST
Once Bug 770746 lands we should change libraries; I think that would be good enough.
Comment 11 Andy McKay [:andym] 2013-02-04 14:39:52 PST
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?
Comment 12 Kumar McMillan [:kumar] (needinfo all the things) 2013-02-05 11:15:46 PST
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.
Comment 13 Wil Clouser [:clouserw] 2013-03-18 13:25:28 PDT
What is the status of this bug?
Comment 14 Kumar McMillan [:kumar] (needinfo all the things) 2013-03-22 16:18:22 PDT
We'd like to get a patch in for this because it will greatly enhance the security of the receiptverifier lib. See comment #12
Comment 15 Ian Bicking (:ianb) 2013-04-10 11:46:27 PDT
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.
Comment 16 Andy McKay [:andym] 2013-04-10 17:25:18 PDT
Thanks Ian, does it cope with subdomains as well as per comment 12?
Comment 17 Ian Bicking (:ianb) 2013-04-10 18:52:16 PDT
Err... no, it's a straight origin check.  I suppose I could do subdomains, as a subdomain si probably harmless in this case.
Comment 18 Kumar McMillan [:kumar] (needinfo all the things) 2013-04-11 07:40:19 PDT
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.
Comment 19 Ian Bicking (:ianb) 2013-04-11 14:56:40 PDT
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).
Comment 20 Andy McKay [:andym] 2013-04-11 15:25:42 PDT
Woot, thanks.

Note You need to log in before you can comment on or make changes to this bug.