Server receipt verification or Apple's VerificationController.m? - ios

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+

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.

Related

Validate App Store Receipt: Local vs Server

This is for tvOS but the same would apply for iOS too. This concerns in-app purchase subscriptions (auto-renewable).
Apple says:
Warning
Do not call the App Store server verifyReceipt endpoint from your app.
You can't build a trusted connection between a user’s device and the
App Store directly, because you don’t control either end of that
connection, which makes it susceptible to a man-in-the-middle attack.
If I use my own server, how is a man-in-the-middle any harder to do? My server will send the receipt to Apple, get all the internal fields as a response but will eventually have to send a valid/invalid response back to my app that anyone could forge with a man-in-the-middle system.
So why is using an intermediate server so much better?
There isn’t supposed to send back a response with valid/invalid result. You should build your API architecture considering subscription benefits: backend makes a decision what content a client app will have.
For example, you have an app with video library. Some videos are free, other available only with subscription. Backend has to send json where each video has a flag isAvailable (true/false). If a content is available, json will have URL for playing. Otherwise, there isn’t any URLs in JSON for non subscribing user, he would have only option to subscribe.
Only backend validates a subscription receipt and decides how much content user get. Client doesn’t know anything about user’s subscription and depends only on JSON from a server.
If someone tried to hack you, they would get nothing without subscription.
In addition, you can use SSL pinning for protection from Man-in-the-Middle attacks (of course, it’s not ultimate solution, but you can make hacker’s lives much more harder).

Is there a way to verify that an Identifier for Vendor (IDFV) is valid?

Apple has a unique identifier called the Identifier For Vendor (IDFV) discussed in this developers guide.
http://possiblemobile.com/2013/04/unique-identifiers/
I was thinking to would be possible to use with a Restful API so only requests that have a valid IDFV are accepted. But here is the problem I don't know any way to verify the IDFV. I could make it so when the app is installed it registers with my service. But ideally there would be a way I can verify this identifier.
I just had a brain storm on this: It's not all that simple, but what if you have an In-App Purchase for the app where that IAP is on a free tier. Have to investigate this more, but I think you can have a Non-Consumable purchase type that is free. The client can then send the purchase receipt (which is encrypted, as of iOS7) to the server side and the server side can then validate this receipt-- Apple does provide a RESTful means of doing this. Thoughts? Of course, you can also make the IAP have some > 0 price. This would give the app developer the means to add a payment mechanism.
I am not sure what your problem is. The app grabs the identifierForVendor and sends it to your server. What else can happen? You could certainly code the transmission so it also sent a hash of the identifierForVendor and some secret string (like "my secret 25671566") to test that the transmission was coming from your app.
You should also know that 1) the identifierForVendor will change if the app is deleted and reinstalled. 2) the keychain might solve the problem of #1 3) The app has a receipt, all apps do whether or not they have purchased an IAP. The receipt is encoded using the identifierForVendor. You could send the receipt from the device along with the purported identifierForVendor and see if it can be decoded. But see paragraph 1 above.

Attack Protection for iOS In-App Purchases

Apple's iOS in-app purchase system has been attacked in the past by people who have tricked apps into giving them content for free. They have since improved the systems involved to try to limit this kind of thing.
I've read through the StoreKit reference documents available from Apple and I have a general idea of the workflow and the checks that need to be done, and so on. However, there may be security issues that I'm not aware of.
Can anyone provide a full list of theft-attacks that can be attempted against In-App purchase mechanisms, how developers might mistakenly allow these attacks, and what are best practices for preventing them?
These are the attacks that I am aware of, past and present:
Fake App Store
Made famous by the Russian programmer Alexey Borodin, this attack only affects apps that verify purchase receipts directly with the App Store. By modifying the DNS settings of the device, and installing forged security certificates, the verification requests are sent to a fake App Store server, which automatically returns that the purchase is valid. Unsuspecting apps will accept these verification calls and deliver the content to the user.
Commentary
After this exploit was made known in July of 2012, Apple issued updated documentation and advice for developers to ensure this kind of attack would not continue to occur. Borodin has been quoted in various web articles as stating that the "game is over" based on Apple's updated APIs and best practices guidelines.
Prevention
Apple has an entire document dedicated to this loophole here. (EDIT: Link is down, Wayback if you want...although the document covered iOS 5.1 and earlier.) The biggest point they bring up is having your app send the receipt to an external server that you own, and then having your server verify the receipt with Apple. However, if you do send the receipt directly from the app to the App Store, they recommend the following checks:
Check that the SSL certificate used to connect to the App Store server is an EV certificate.
Check that the information returned from validation matches the information in the SKPayment object.
Check that the receipt has a valid signature.
Check that new transactions have a unique transaction ID.
Fake Verification Server
If your app sends the transaction receipts to your server, which then forwards them to the App Store, one option is for the attacker to fake your verification server. By some method (altering the DNS table, changing the URL, etc.) the receipt is sent to an alternate location and a "successful verification" is returned. In this way the receipt never reaches your server and you never have a chance to check it with the App Store.
Commentary
Apparently there are a variety of apps in the Cydia store that serve to run in the background, monitor receipt traffic, and redirect it for this purpose. Source: Hussulinux Blog
Prevention
If you immediately deliver content as soon as a receipt is verified, there is no known way to prevent this kind of attack. However, take this scenario: you have a user account system managed on your own server. If the purpose of the In-App Purchase is to notify your server that a particular user account has purchased an item, and the app downloads that item from your server, you are immune to the attack. Redirecting the receipt to another server will accomplish nothing for the attacker, because your server will never mark the user account as owning an item, as it never sees the receipt.
Fake Receipts
An attacker can fake the purchase process and then send a forged receipt to your verification server. Unlike the previous attack, the receipt's outbound location is not changed, but it is replaced with an imposter. This spoofed receipt is, in fact, a valid receipt from a previous App Store transaction, and the App Store will verify it as such. By faking the purchase process and then sending a spoofed receipt to your server, the content is never actually paid for.
Commentary
Apparently there are a variety of Cydia apps that do this sort of thing. You can spot fake receipts because their product_id is totally different from anything you use in your app. Apparently the most famous spoofed id is com.zeptolab.ctrbonus.superpower1. Source: Hussulinux Blog.
Prevention
In the link where I found this attack, the blogger recommended that you unpack the receipt at your verification server (base64_decode) and check the product_id before sending the receipt to the App Store. However, in this article Apple recommends that you first send the receipt to the App Store, and then read the returned information to be certain that the receipt is valid.
(Also, correct me if I'm wrong, but Apple's recommended technique could also be used to prevent this kind of attack even if you don't have a verification server. If your app sends the receipt directly to the App Store, it could examine the contents of the JSON response to ensure it's valid. But this goes against Apple's recommended best practices of using an external verification server, so I wouldn't advocate it.)
In Closing
These are the attacks that I'm aware of, feel free to correct me if I'm wrong on any point or to put forth additional attacks and fixes.
As a note, there's this website: http://www.in-appstore.com/ which claims to allow in-app purchases for free, either on iOS 5 or with a jailbroken iOS 6 device, and is active as of July 5th, 2013. While I'm not 100% sure how they are doing it, it definitely seems to involve DNS rerouting and faked security certificates, which would imply Fake App Store or Fake Verification Server, which would additionally imply that there are still apps out there that are not secured against these attacks.
Resources
Apple iOS in-app purchase hacking
My Experiences With Verifying In-App Purchase Receipts
How to detect "IAP Crackers"?
EDIT:
Additional
It seems like one or two people have swung by here and found this post useful, and I'm glad.
There's more information that can be had on this subject, either in other posts, books, or, if you're up to it, scouring the underbelly of the internet. Here's just a couple of websites and posts and so forth that I want to look into, but haven't had a chance yet. I'll add more links later when I find interesting tidbits.
http://www.se7ensins.com/forums/threads/tut-how-to-hack-ios-games-and-apps.701845/
http://www.iapphacks.com/
A couple of immediate takeaways: don't store your player's data in a simple plist unless you want it to be edited by some teenager. People don't have to hack your IAP system if they can just give themselves gold or something similar by editing the files on the disk. Perhaps by encrypting these files, you could discourage a certain segment of attackers.
Based on the se7ensins link, it seems as though an attacker can also pry apart your binary and mess with it to achieve the same ends as editing a plist file, or even more, but this will require a slightly higher skill level. Perhaps setting up jailbreak detection would suffice to deter most people who would resort to this.
Again, this section is mostly speculation, but it may help someone. Really, the level of protection you have depends on how far a developer is willing to go (down the rabbit hole of security and encryption) to protect their bottom line.

Best practices in Server side validation of In app purchase in iOS

We are using server side validation of the payment like so -
User makes payment.
Store kit API sends transaction receipt to App.
App sends base64 encoded transaction receipt to our server.
Our server calls https://buy.itunes.apple.com/verifyReceipt and validates the transaction recept.
User is marked as paid.
For a particular user, we didn't get the transaction receipt at the server, due to which the receipt couldn't be verified. We are guessing something went wrong in steps 2 and 3.
If there were connection problems at the time of sending receipt to server, the app retries again on subsequent app resume.
Now we have one missing transaction receipt and an angry user. How do you suggest we go forward? How can we prevent this in future? Are there any guidelines or best practices that we can follow to prevent such situation?
Thank you.
Based on my experience, the likely issues are
The base64 data got url-encoded along the way and so + and / got messed up - replace these with safer characters before transfer
The whole transaction is bogus.
The way to check for the second case is to look at your account and see if there is a matching purchase record. Unfortunately, the web site can be a bit difficult to review unless you have a low purchase volume.
The are two things you need in your code to correctly handle errors on your server or on, if it happens, Apple's end.
Do not call finishTransaction: until you have successfully communicated with your server (it wouldn't help in this case but worth noting)
Have a "Reload Purchases" button or action that calls restoreCompletedTransactions: on the SKPaymentQueue defaultQueue. For non-consumable/entitlement objects, this will resend all transactions with receipts that can be re-verified on your server.
If the problem you are facing is with non-consumables/entitlements, then the second item is the way out.

Verifying In App Purchase Receipt from Client

I read (almost) all the answers on verifying in-app purchase, and actually I already implement it in a server-side fashion. But managing a server sometimes could be too much expensive, and in theory you could do the verify from your app: basically is just sending a json to Apple and get the answer back.
Of course I know that on jailbroken devices the receipts may be fake (that's why you verify them) but (I beg pardon my ignorance) why I can't trust an https connection to the Apple server?
I mean if the user hack my app, there's no real way to be sure of anything, but if the hack is a general method to provide fake receipts testing with Apple could be enough right?
To be clear, what is the security level of an in-app verify of recipts? Can it add some degree of protection os is useless?
This answer explains quite well why you must use server side checking to limit the effect of some "general purpose" crackers, like "IAP cracker"; besides chaining the iTunes json request in your content delivery API is quite convenient and the answer is fast.
Of course if your aim is to provide some content already in the app but locked, you may feel it is not convenient to setup a server specifically for this, but I will ask you to do this experiment:
make an app with some good content and this content already locked in the app (so no content server need)
add some analytics just to track the usage of this locked feature
after some month, compare the number of purchases with the number of new users using the paid feature.
at this point it will be clear for you that adding a server script just for receipt validation is a good investment; besides there are some services, which are very cheap (e.g.: urban airship) we already do this for you, so you don't need to setup an hardware for this.
I hack inapp cracker and discover a way to block it client side: the receipts and transaction IDs it creates have a predictable scheme that's easy to spot. I put all the details here:
spot fake receipts client side
update
hope this helps

Resources