We have an iPhone app that offers in-app-purchase (IAP) products. We perform IAP validation through our server that contacts Apple IAP receipt validation server.
We get many transactions using the exact the same receipt. We suspect it is the receipt used by the Russian hacker that managed to bypass Apple IAP validation server on July 2012. Apple validation server approves the receipt, so we currently perform our own check and deny the purchase if the receipt is equal to this receipt.
Has anyone else experienced the same problem? is our assumption true? is there any other way to protect against transactions using this receipt and maybe similar other receipts?
The suspicious receipt starts with the following characters (total 3045 characters):
ewoJInNpZ25hdHVyZSIgPSAiQXBkeEpkdE53UFUyckE1L2NuM2tJTzFPVGsyNWZlREthMGFhZ3l5UnZlV2xjRmxnbHY2UkY2em5raUJTM3VtOVVjN3BWb2IrUHFaUjJUOHd5VnJITnBsb2YzRFgzSXFET2xXcSs5MGE3WWwrcXJSN0E3ald3dml3NzA4UFMrNjdQeUhSbmhPL0c3YlZxZ1JwRXI2RXVGeWJpVTFGWEFpWEpjNmxzMVlBc3NReEFBQURWekNDQTFNd2dnSTdvQU1DQVFJQ0NHVVVrVTNaV0FTMU1BMEdDU3FHU0liM0RRRUJCUVVBTUg4eEN6QUpCZ05WQkFZVEFsVlRNUk13RVFZRFZRUUtEQXBCY0hCc1pTQkpibU11TVNZd0pBWURWUVFMREIxQmNIQnNaU0JEWlhKMGFXWnBZMkYwYVc5dUlFRjFkR2h2Y21s
It's possible that a person is unlocking the in app purchase for his or her friends, or that there is a hacker, or anything. But if you've blocked the receipt, you should be fine unless another receipt pops up with the same problem. I'm currently having a similar problem with receipt verification. For some reason, receipts from Cut the Rope are being verified against my server, but as my server doesn't recognize the product identifier, it doesn't unlock anything.
There really is no way to prevent this from happening as the receipt the hacker used was valid. You can only monitor your database and block problematic receipts as they arise. The only way to automatically prevent this is to block a certain receipt if it is being used many times within a short period of time.
Related
In iTunes Connect it is possible to give a free trial period for autorenewable subscriptions.
App > Manage In App Purchases > Subscription Basic > 1 Month > Offer a free trial?
How can I get this information on the client? SKProduct does not have any information about this as I can see. Since we're having a marketing campaign it is very confusing for the end user to not see information about the product has a trial period.
Of course it is possible to fetch this kind of information from a server I maintain, but then we'll have the overhead with updating both our server and iTunes Connect. So I don't accept this kind of answer unless it is wired up to retrieving that trial period information from Apple's services.
TLDR; It is not possible. You need to manage this information yourself.
When you process an SKPayment you get back a receipt. You should verify those receipts regularly for subscriptions (e.g. before downloading new content) as the user might have cancelled the subscription. When the user does cancel the subscription or the subscription expires you get back a descriptive error when verifying the purchase's receipt.
Moreover the receipt gives you all the information you need: for a given product you know which trial period you grant. Therefore when a purchase is made you could store the purchase date given from the purchase receipt in your model object or in the NSUserDefaults or in the Keychain alongside the purchase data. At this point you know when the trial is expired and verify that the subscription is still valid. If you can't you might want to disable access to the content until you're able to do so.
For more informations about purchase receipts and subscriptions check out the In-App Purchase Guide by Apple.
On the client side you usually identify the different products and characteristics by their product identifier as the App Store does not deliver certain information such as subscription period and free trial period.
So if your product ID is for example:
com.domain.app.product_paid1month_free7days you split the ID on the client side and know that the paid subscription duration is 1 month and the product has a free trial period of 7 days.
Of course one approach would be to transmit the product ID to your own server to get its characteristics as response. This way you can maintain the product list continuously without updating the binary and across versions.
SKProduct > introductoryPrice
Available since iOS 11.2
https://developer.apple.com/documentation/storekit/skproduct/2936878-introductoryprice?language=objc
I'm currently implementing a non-renewable in-app purchase and am a little concerned over the following scenario (or variation thereof):
User purchases my non-renewing in-app purchase. I save the receipt to NSUserDefaults, but before I have sent it to my own server for verification (and account functionality activation) the user loses signal/my server is down and in the meantime breaks their device/uninstalls my app (thus erasing the stored NSUserDefaults).
As far as I can tell you cannot restore a non-renewable purchase as with other types of IAP, so the user has lost the money they spent on that purchase as there is no way for me to know that it was ever made.
Am I missing something here, or am I to assume the above scenario is unlikely enough that I needn't worry about it?
Thanks
Ok, after some further reading it appears that the solution is to not call finishTransaction on the SKPaymentTransaction until I have had confirmation from my server. This way, the transaction should remain in the transaction queue across devices/installations until I have registered it within my own system.
I have tested and seems there is no need to store the receipt to complete the payment flow.
So what is the real purpose of the receipt?
Jailbroken phones are everywhere, and some of them are enabling user to successfully complete in-app purchase without any real connection to Apple server, by replacing original API with dummy one that return fake receipt. By that, you should get the idea already how receipt and the receipt verification is useful.
The point of the receipt is for your server to verify the validity of the transaction with apple should you so desire and, as #Daniel put it short and sweet, book keeping.
I was looking to this thread.
It's stated that the App Store calls the paymentQueue and posts a transaction with transaction.transactionState==SKPaymentTransactionStateRestored.
But I'm not getting those calls. I'm testing
with sandbox accounts/subscriptions, that expire and are auto-renewed every 3 minutes;
WITHOUT verifying receipts.
This way, my updatedTransaction method is never called after the first buy.
Anyway, if I later on restore completed transactions, I get all the receipts.
Any experience with sandbox? Also, the point 2) is needed or (as I think) it's optional?
The state: SKPaymentTransactionStateRestored is only determined if you have the receipt on the user's device and you use it to make the transaction. If you do not have the receipt, then you will need to call restoreCompletedTransactions to decide whether to apply the auto-renewed subscription.
The situation when you won't have a receipt is when the user buys an auto-renewable subscription, then deletes the app or installs the app on a different device. In other cases, you can safely store the receipt on the device.
The issue is detecting the case when the user has purchased an auto-renewing subscription and needs to have the content activated. Without a receipt, if you trigger the transaction, it will fail with the state SKPaymentTransactionStateFailed. Looking at the error code, you will see SKErrorPaymentCancelled. This, as far as I can tell, is a bug on Apple's part. You will need to make the best decision for your app to deal with it :/
In the this Article Apple wrote how to enable an auto-renewing subscription from the users point of view. But my question is how to handle this auto-renewing subscription as the developer of an app?
In my app (currently in developing) the user can buy some subscriptions (30 days, 3 months and 1 year) via in-app-purchase. After a successful payment I send the bought item identifier to my server to save the new subscription time (also used for other platforms). This works perfectly in the sandbox-environment.
But if I correctly understand the article the auto-renewing subscriptions is performed from inside the AppStore and inside my app. How can I now track the subscription?
If a subscription is autorenewed, the transaction won't pass the paymentQueue:updateTransactions method. The renew just happens on the Store.
If you want to test for it you have to either:
Revalidate the receipt on your application server, if you store the receipt there.
Revalidate the receipt on your iOS client
See: http://developer.apple.com/library/ios/#documentation/NetworkingInternet/Conceptual/StoreKitGuide/VerifyingStoreReceipts/VerifyingStoreReceipts.html#//apple_ref/doc/uid/TP40008267-CH104-SW1
In order to avoid testing for an autorenew each launch/activation you should store the endDate of the subscription period to test for a renew afterwards.
Also see: http://developer.apple.com/library/ios/#documentation/NetworkingInternet/Conceptual/StoreKitGuide/RenewableSubscriptions/RenewableSubscriptions.html#//apple_ref/doc/uid/TP40008267-CH4-SW4
However, there seems to be a bug in the sandbox. Subscriptions sometimes get renewed, sometimes not. Hard to test....
based on the (rather scant) info found in apple's in-app-purchase documentation, my impression is that whenever you need to determine the state of a user's auto-renewal subscription, you would restore their transactions.
this would cause the app store to send all auto-renewal transactions to your app, at which point you would process the receipts and make the appropriate content available.
presumably, you would only need to do this when the user's current subscription (which you can track locally) is set to expire, or when they are first installing the app.