Is it OK to store In-App purchase receipts into CloudKit?

I'm developing an app that uses CloudKit. Its a free app with consumable and non-renewable subscription in-app purchas to unlock app functionality. Here's my thinking of the in-app purchase flow:


user buy IAP consumable/non-renewable subscription -> validate the receipt via my own server with iTunes server -> store the receipt into CloudKit user's own privateDB -> unlock app features


This will simplify my own server for just receipt validation, there is no need to create user account to store consumable and non-renewable subscription info. If the user sign in using a different device, the app will retrieve the receipts (especially for non-renewable subscription) from the CloudKit and unlock app features.


Is it OK flow? Is it prone to spoof or man-in-middle attack?

two things:

1) You will need to transmit the receipt from the device to your server (and back) using a 'secure method' to assure that the communication is to/from your server and modified by a man-in-the-middle. To do this, you could transmit a packet of three objects - the encoded receipt (ER), a random number selected by the device (RN), and the hash of the receipt+the random number. Then have your server return two objects - the decoded receipt (DR) and the hash of the decoded receipt+the random number. Your server checks the hash to be sure that the ER is associated with the RN. The device checks the hash to be sure that the DC is associated with the correct RN. This prevents a man-in-the-middle from 1) replacing the ER with a different, valid receipt and handing it to the server or 2) replacing the packet from your device with a different, valid packet and handing that to the server or 3) replacing the DC with a different, valid DC and handing that back to your device and 4) replacing the packet from your server with a different, valid packet and handing that back to your device. The hash can be any procedure known only by your app and your server - for example you could use a SHA1 hash and include some shared secret like your middle name. The 'hash' procedure needs to yield a different value for any different RN and ER (or DC).

2) you will need to tell your server when it is validating an original receipt (that might be a duplicate fed into your device's updatedTransaction method) and when it is validating a receipt coming from CloudKit. In the first case, your server will keep a record of the transaction_id and not approve a duplicate. In the second case this test doesn't matter.


Alternatively, you could consider this overkill and just use CloudKit (or the key-value file in iCloud) to copy your IAPs to other device logged into the same iCloud Account.

For things like unlocking app features, just use a normal, non-consumable purchase, and then it will show up on new devices tied to the same iTunes account as soon as the user does a "restore purchases" without you having to implement any special storage at all.


For consumables, it might make sense to use iCloud that way, with the caveat that if you sell someone 1,000 tokens on device A and then they associate device B, they can then turn off the network, play your game, and use 1,000 tokens on each device, for a total of 2,000 tokens. If you don't care about that, then by all means, go for it. But consumables are more typically treated as per-device for that reason (and explicitly not stored on any sort of account server).

I allow devices to exchange consumable tokens through their iCloud Account. They buy 100. They store 30 on the cloud (and have 70 left on the device). They access the cloud with a different device and download 10 of the 30 to that device leaving 20 on the cloud.

Is it OK to store In-App purchase receipts into CloudKit?
 
 
Q