Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Prevent replay attacks appStoreReceiptURL app receipts

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?

like image 887
Dan Fabulich Avatar asked Apr 17 '18 04:04

Dan Fabulich


1 Answers

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.

like image 82
Dan Fabulich Avatar answered Sep 28 '22 02:09

Dan Fabulich