We have a server-side service that we only want to offer to valid users of our paid iOS app. (Note that this is a paid iOS app, not a free app with IAP.)
When we use appStoreReceiptURL
to check the sandbox app receipt and send it to our server side, we see a receipt like this:
{
"receipt_type": "ProductionSandbox",
"adam_id": 0,
"app_item_id": 0,
"bundle_id": "com.example.myapp",
"application_version": "1.1.1",
"download_id": 0,
"version_external_identifier": 0,
"receipt_creation_date": "2018-04-16 23:53:58 Etc/GMT",
"receipt_creation_date_ms": "1523922838000",
"receipt_creation_date_pst": "2018-04-16 16:53:58 America/Los_Angeles",
"request_date": "2018-04-17 03:25:42 Etc/GMT",
"request_date_ms": "1523935542798",
"request_date_pst": "2018-04-16 20:25:42 America/Los_Angeles",
"original_purchase_date": "2013-08-01 07:00:00 Etc/GMT",
"original_purchase_date_ms": "1375340400000",
"original_purchase_date_pst": "2013-08-01 00:00:00 America/Los_Angeles",
"original_application_version": "1.0",
"in_app": []
}
I'm concerned about replay attacks with this receipt. In a replay attack, one device purchases the app and submits a valid receipt, but a second unauthorized device stores and transmits an exact copy of the first receipt. Since the first receipt is signed by Apple, the duplicate appears valid.
Ideally, we'd defeat a replay attack by observing a unique identifier in the receipt; if someone attempts to retransmit the same receipt ID, we'd know that it's a duplicate. IAP receipts include a transaction_identifier
field for exactly this reason.
But there appears to be no unique identifier that we can use to recognize replay attacks with paid-app receipts. Hackers can retransmit this receipt to us from different devices and we'll have no way of knowing whether it's a duplicated receipt or a new, original receipt.
Having said this, my eye is drawn to those _id
numbers that are 0 in the sandbox receipt: adam_id
, app_item_id
, and download_id
. Can we use any of those to recognize duplicate receipts? Or is there some other, better way of handling this?
It's impossible to detect duplicate receipts for paid apps. The adam_id
, app_item_id
, and download_id
are undocumented, and so developers can't rely on them for security purposes. This is unlike IAP receipts, which include a transaction_identifier
that can be deduplicated.
There is a possible workaround, though. You can offer users non-consumable IAP that costs $0 (Free), and require users to "buy" it in order to access server-side functionality. Since it's a non-consumable IAP, each paid-app user can purchase it at most once.
It's a bit of a hassle for users to agree to the free "purchase" and to sign in to the App Store to access it, but once they do, they'll own an IAP tied to their paid-app receipt. The free IAP receipt includes a transaction identifier; the server can use the transaction ID to deduplicate purchases.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With