views:

2285

answers:

4

Look at Apple's diagram for the server purchase model.

In step #9, how can the server know that it is really talking with an iPhone that is entitled to the purchase, and that Eve is not performing a replay with a dishonestly obtained receipt?

The receipt may be valid, but that doesn't prove that the sender is the entitled party.

Is there any notion of a device certificate on the iPhone that can be used to sign the receipt?

Is there any way to bind the receipt to the device, or bind the receipt to both the iTunes account and to the device, so the server can validate?

A: 

I'm wrestling with the same questions right now. Have you made any progress on answering them?

I could ask the user for a user name and password, use https and essentially have them log in, but all I really need to know is if the http request is from a real device. The login mechanism (though maybe it only needs to be done once) seems like hurdle I don't need to give my users.

Ruug
No progress yet. My biz partner was supposed to talk with an 'evangelist' today, but I have not heard back yet. You can do user auth. It is inappropriate for some applications and causes server-side state. User auth can largely plug the hole, though.
jeff7091
+5  A: 

Apple-Provided Vulnerable Approach

The server can authenticate a purchase by doing the following:

  1. The iPhone application receives a transactionReceipt after the purchase. Have the iPhone base64 encode it (You can use this open-source addition to NSData) and send it to your server. (You could even send it as-is and have the server base64 encode it before validation.)

  2. Have your server send a JSON request with the single key receipt-data with the base64 encoded transactionReceipt to https://buy.itunes.apple.com/verifyReceipt using an HTTP POST. (For directions on how to do this in various server-side languages see this site)

  3. The server will respond with a JSON object with two keys: status which is an integer and receipt which is the receipt repeated.

If status is zero, the receipt is valid should be accepted, a non-zero value means the receipt isn't valid.

Secure Additions to Apple's Approach

However, there are a few security implications. A user could use another user's receipt since devices aren't tied to receipts, or a user could use another product's receipt since the server doesn't verify the product id of the receipt. To ensure this doesn't happen you should also do the following:

  1. When you first get the receipt in the application, immediately send it to your server along with the device's UUID over a secure channel such as HTTPS or an SSL socket. Do not store it anywhere, leave it in memory.

  2. On your server, store the UUID and receipt pair in a database.

  3. When a device sends a UUID and receipt pair, verify with your database that the receipt has not already been used, and make sure the receipt is actually for your product by checking the receipt's product id. The receipt is just a JSON object, so your server can read the contents by decoding the receipt from base64.

  4. Return a response to the device over the secure channel telling it whether the purchase is:

    • Authenticated as new (wasn't in DB and was valid)
    • Authenticated in the past (Same UUID and receipt pair was already in DB)
    • Denied due to wrong product id
    • Denied due to having already used the receipt with another UUID.

Since the receipt is only ever in memory on the device, and your application uses the device's UUID (can be spoofed by jailbroken devices, see comments), and all purchases of your product are logged with the device's UUID on your server in a secure manner; a user could not use another user's receipt to verify the purchase, nor could they use a receipt from another product, since you check for that.

You can also validate other fields from the receipt if you want to verify other details of the transaction. For example, if your product is a subscription, you'll like want to look at the transaction date as well.

Also, users cannot pretend to be your server by having the device on a private network with a host of the same name as yours, since they won't have your SSL certificate.

Failure Considerations

Since failure might occur between when the user's device gets the receipt and verifying it with your server (for example if the user looses connectivity, or your server is down for maintenance), you should also let the user "re-authorize". Re-authorizing should get the receipt from the store (using a Restored Transaction) and re-send it to the server just as though this was a new purchase. This should rarely need to be used, but should be available to save the user having to re-buy the product in the case of network failure.

Multiple Devices Consideration

This means that if a user wants to use an application on more than one device, they will have to purchase the product multiple times. This might be the desired effect, but you should likely inform your users before they purchase since they might expect to be able to use the content across devices they have associated with their account.

If the receipt also contains the iTunes account information, authentication could use that to allow users to share content between all their devices (but not their friends').

Ben S
no dice! one can validate the receipt, but that does not authenticate the iphone or user of the iphone. if I, Eve, am able to intercept or otherwise obtain a valid receipt, then I can give it to all my friends, and we can all get the content without purchasing anything.
jeff7091
I added some security enhancements to Apple's vulnerable explanation.
Ben S
I am not sure if I understand your approach with device's UUID correctly. My understanding is that you are allowed to install an application on multiple devices without extra cost. Also restricting application to device UUID would mean that if you upgrade/change your phone you need to purchase all the apps again.
kristof
@kristof: You're right, but this is the only way to securely verify a receipt since it can't be spoofed. If Apple included the iTunes account in the receipt, or if there was a secure way to verify that a given device UUID is associated to same iTunes account as another device, you could securely verify purchases across all devices associated with a given iTunes account, but that's not the case. Maybe in a future update this will be made available.
Ben S
@kristof: If I understand correctly, the app can be installed on multiple devices, but a _subscription_ can only be per-device. (There are no Restored Transactions for subscriptions AFAIK.)
Joe D'Andrea
@jdandrea: You're right: "If the user attempts to purchase a nonconsumable item they have already purchased, your application receives a regular transaction for that item, not a restore transaction. However, the user is not charged again for that product. Your application should treat these transactions identically to those of the original transaction." Source: http://developer.apple.com/iphone/library/documentation/NetworkingInternet/Conceptual/StoreKitGuide/MakingaPurchase/MakingaPurchase.html#//apple_ref/doc/uid/TP40008267-CH3-SW2
Ben S
It seems that the UUID can be spoofed on rooted devices (http://www.theiphonespot.net/2009/09/18/udid-faker/), rendering this scheme moot.
Ben S
correct - hence the question - how to authenticate the device :-). UDID adds nothing for us.
jeff7091
I suspect this may be why apple doesn't want in-app purchase to be used for non-digital products.
Carl Coryell-Martin
Digital product have value - they seem to be not well protected by this Apple design.
jeff7091
UDID can be spoofed w/out a jailbroken device. As the server, you don't know what code is actually running on the mobile. It could be sending whatever it wants for a UDID value.
jeff7091
A: 

I do not think that can bind the receipt to the device.

My understanding is that you are allowed to install an application on multiple devices without extra cost. Binding it to the device would mean that if you for example upgrade/change your phone you would need to purchase all the apps again.

kristof
the problem is, I cannot limit the number of devices, because I cannot authenticate. If the receipt is in the wild, 1,000 devices could pull the content.
jeff7091
A: 

Hay how to send Transition receipt along with product identifier to my server using HTTP Post method weather i have to encode product identifier using base 64...?

jeeva