Roger Gilbrat
Roger Gilbrat

Reputation: 3835

Server receipt verification or Apple's VerificationController.m?

If I implement Apple's VerificationController.m example, is it still necessary to do server side receipt verification? Also, if you do server side, then there seems to be no reason to implement VerificationController.m since you're not contacting Apple's servers from the device.

Best case, I'd rather only implement VerificationController.m because I don't have a great way to run my own https server. Is that enough? The App runs on iOS 5+

Upvotes: 2

Views: 1440

Answers (1)

tc.
tc.

Reputation: 33592

This is trickier than it first appears, so I'll probably get this subtly wrong, but here goes:

The original attack relies on two weaknesses in iOS ≤ 5.x:

  • Failure to check that the App Store server is genuine (the user/attacker is allowed to install CA certificates, circumventing the SSL certificate check).
  • Failure to check that the receipt is valid for that device.

This allows the user/attacker to pretend to be the App Store server and present a valid receipt for someone else's purchase.

VerificationController can't fix the first weakness (it can't change how StoreKit talks to Apple); it mostly just fixes the second. It also seems to check far more things than ought to be necessary (but I could just be plain wrong here), including a bunch of things that StoreKit probably already checks.

Client-side verification doesn't protect against someone hacking the client, which is pretty easy on a jailbroken phone. This isn't really an issue if the thing being purchased could be hacked just as easily (e.g. ammo for a game/turning off ads).

Server-side verification is desirable when the server provides the thing being purchased (e.g. DLC/Skype credit/FarmCoins).

  • For consumables, the server needs to ensure that the transaction only gets applied to one account; checking device IDs is a bit superfluous — the attacker would need to submit the transaction receipt before the purchaser does, which either involves the purchaser handing over the receipt (not really an attack) or the attacker stealing the receipt with an attack on SSL (which would mean far bigger things to worry about).
  • For non-consumables (e.g. DLC), you'll want to verify the device ID as well. This can be as simple as the client sending its device ID to the server — this doesn't protect against a hacked client, but the attacker can just forge the device ID or pirate the DLC.

In general, do the verification at the point where you convert the receipt into the purchased item.

There are a few issues with VerificationController, though:

  • It checks that the receipt-verification server is using an EV certificate, but doesn't do any other SSL-layer checks. I don't know if the user can install an EV-capable CA certificate (and it won't be long until an EV CA is compromised).
  • You have to embed your receipt-verification password in the app (search for "password" and "ITC_CONTENT_PROVIDER_SHARED_SECRET"), which is trivial to extract on a jailbroken phone. I'm not sure what bad things an attacker could use this for, but surely the point of a secret is that it's secret!
  • Transactions which it has "seen before" are considered invalid, but it marks transactions as "seen" before contacting the receipt-verification server! This means you never reach //Validation suceeded. Unlock content here. if the receipt-verification connection fails, which could easily happen over a poor 3G connection. This might not be an issue for non-consumable transactions (I think restored transactions get a new transaction ID), but means consumables get lost forever. You can postpone calling -[SKPaymentQueue finishTransaction:] until receipt-verification succeeds, but this will leave incomplete transactions in the queue — hopefully they eventually expire without charging the user.
  • It trusts the contents of NSUserDefaults. This is part of the app backup and easily editable.
  • It assumes that -connection:didReceiveData: returns all the response data. This might be true to implementation details of the server and NSURLConnection, but relying on this is unwise.

Upvotes: 3

Related Questions