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).
So my client wants an app that works like this:
one user presses a button on his device
other user(s) get a push notification
no third party server
So I have been looking into the Apple Push Notification Service but I don't want to have a third party "provider" server. Would it be possible for an iPhone to act as a "provider"?
I have already looked at this question which sounds like what I want to do but I am not satisfied with the answer. More specifically:
Would encrypting the APNs key with another key hardcoded into the app be secure enough? Any other ideas for dealing with that issue?
The tokens will always stay the same for a given app for a given device, right? If that's the case, I can deal with creating the token database. If that's not the case, my app won't work.
Will Apple accept such an app?
Would encrypting the APNs key with another key hardcoded into the app be secure enough?
I believe the main issue is you'll need to deliver APNS certificate and private key with your app, and renew it when needed (on all devices). Regardless of it being encrypted or not, if it is available for your app, it might become available for attacker (by dumping its plaintext representation from memory, or by disassembling your decryption code) and make it possible to impersonate your app. So no, it is not secure.
The tokens will always stay the same for a given app for a given device, right?
Not really. Documentation claims that a device token is not a unique ID that you can use to identify a device. Device tokens can change after updating the operating system on a device. As a result, apps should send their device token.
Will Apple accept such an app?
I believe there were no precedents because of the reasons above.
I have two Applications in iTunes. A free version and a paid version. The paid version does not have advertisement. The two versions have different App Ids.
I have set up APNS for one of the App Ids. How can I handle notifications for both Apps?
Each application requires its own certificate (since each App Id has its own push certificates).
Therefore, your server will have to hold a different certificate for each App, and maintain a separate connection with the APNs server for each App (since you use the certificate to open the connection).
This means that when one of your apps sends a device token to your server, you have to know which app sent the device token, and mark it accordingly in your DB (in order to know which connection to the APNs server to use when pushing a notification to that device).
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.
I want to validate iOS in-app-purchases using my own server. The iOS app will talk to my server which in turn will talk to Apple's server to determine if the IAP is valid. I'm fairly new to networking so I have a basic question: How can I make sure my iOS app is talking to my server securely?
I imagine the app will talk over https but I don't know how this works. Any advice on setting up https communication between the two (or alternate methods of secure communication) are greatly appreciated!
Lawson has a point. You can't make your server perform the purchases directly at the AppStore. That has to be performed by your app.
It should request the available product identifiers from your server and then send an SKProductsRequest to the AppStore.
If required it processes the purchase over the app store and tells your own server about it by sending a so called receipt. The server can validate the receipt directly at the AppStore. But that is the only thing the server can do it self at the AppStore.
You can read more about it here: Overview of In-App Purchase: Server Product Model
As for the connection between your app and your server, I don't think you have much of a (reasonable) choice but to use SSL. Almost anything more secure would require a PKI.
Sorry about the previous answer... I misread your question. You can have your server send a POST request to Apple's server, then parse the response.
https://developer.apple.com/library/content/releasenotes/General/ValidateAppStoreReceipt/Chapters/ValidateRemotely.html