What steps to perform for the upcoming changes to the App Store receipt signing intermediate certificate?

Currently, my app validates App Store receipts on the device, so as per this news, I need to make changes to it,

But I am unable to make a decision on where I should start, Can anyone please help me out on this?

Do I need to make changes in the device receipt validation? If yes, what steps should I take?

OR

Should I do the receipt validation from the server side? If yes, then what steps to follow to make a receipt validation on the server?

Your suggestions will be highly appreciated.

Accepted Reply

to validate the receipt data, calls the verifyReceipt endpoint

So you aren't doing on-device receipt validation. You're sending the receipt to Apple for validation.

Communicating with the App Store servers from the app is ... not how I do it. I believe you have to embed your "shared secret" into the app, right? That is ... an interesting security decision.

Anyway regarding the current change of SHA algorithm in the intermediate certs, I do not believe it will affect you as you are not doing certificate validation on the device.

Replies

You may need to make changes to your on-device receipt validation, depending on whether your existing validation code will work with the new intermediate certificate or not.

If your existing implementation understands the new intermediate certificate, then you have nothing to do.

How are you validating the certificate? Are you using e.g. libssl?

Thank you @endecotp for your reply, Currently I am using SwiftyStoreKit to handle In-App Purchases.

To make the In-App Purchase, I am calling SwiftyStoreKit's purchaseProduct(_ product: SKProduct) method, And once I get the success response from this method, I am validating the receipt to validate the purchase by this SwiftyStoreKit's verifyReceipt(using validator: ReceiptValidator) method,

Which first fetches the appStoreReceiptData from the Bundle as below,

var appStoreReceiptData: Data? {
        guard let receiptDataURL = Bundle.main.appStoreReceiptURL,
            let data = try? Data(contentsOf: receiptDataURL) else {
            return nil
        }
        return data
    }

Then to validate the receipt data, calls the verifyReceipt endpoint https://buy.itunes.apple.com/verifyReceipt as below,

		let storeURL = URL(string: "https://buy.itunes.apple.com/verifyReceipt")!
		let storeRequest = NSMutableURLRequest(url: storeURL)
		storeRequest.httpMethod = "POST"

        let receipt = appStoreReceiptData.base64EncodedString(options: [])
		let requestContents: NSMutableDictionary = [ "receipt-data": receipt ]
		// password if defined
		if let password = sharedSecret {
			requestContents.setValue(password, forKey: "password")
		}

		// Encore request body
		do {
			storeRequest.httpBody = try JSONSerialization.data(withJSONObject: requestContents, options: [])
		} catch let e {
			completion(.error(error: .requestBodyEncodeError(error: e)))
			return
		}

		// Remote task
		let task = URLSession.shared.dataTask(with: storeRequest as URLRequest) { data, _, error -> Void in

        }
		task.resume()

And once I got the successful validation response from the above method, I unlock the pro content for the user in the application.

Can you please let me know how can I know that how I am validating the certificate?

Also, can you please check the above things, and let me know if I still needs any changes on receipt validation?

Thanks again.

to validate the receipt data, calls the verifyReceipt endpoint

So you aren't doing on-device receipt validation. You're sending the receipt to Apple for validation.

Communicating with the App Store servers from the app is ... not how I do it. I believe you have to embed your "shared secret" into the app, right? That is ... an interesting security decision.

Anyway regarding the current change of SHA algorithm in the intermediate certs, I do not believe it will affect you as you are not doing certificate validation on the device.

@endecotp is correct, that if using verifyReceipt your app will not be impacted as you are not doing local app receipt validation.

Note that generally private keys should be kept secure, if you need to regenerate your shared key, please see this doc for more info: https://developer.apple.com/help/app-store-connect/configure-in-app-purchase-settings/generate-a-shared-secret-to-verify-receipts

Per documentation it is noted to not call the verifyReceipt from the device itself, the request should come from a secure server. https://developer.apple.com/documentation/storekit/in-app_purchase/original_api_for_in-app_purchase/validating_receipts_with_the_app_store

Thank you both of you for the reply, I have got your point that I am sending the receipt to Apple for validation, and this change will not affect my application.

This is very helpful to me.

As I see this documentation Validating receipts with the App Store,

It is saying that

The verifyReceipt endpoint is deprecated

So Is there any end date from which this endpoint will not work?

What should I do?

Should I continue using the verifyReceipt endpoint from the device?

Or

Should I plan to use the verifyReceipt endpoint from my server?

Or

Should I plan to use the App Store Server API and App Store Server Notifications V2?

Can you please share your feedback on this?

Question: does your app rely on having an internet connection while it is running for other purposes?

In my case, my app generally does not need an internet connection. So being able to verify the receipt without an internet connection is important. But if your app cannot do anything useful without an internet connection then also needing the connection for receipt validation is not a big deal.

Yes, my app relies on having an internet connection while it is running.

But my concern here is that,

Should I continue using the verifyReceipt endpoint from the device?

Or

Should I plan to use the verifyReceipt endpoint from my server?

Or

Should I plan to use the App Store Server API and App Store Server Notifications V2?

my app relies on having an internet connection while it is running

In that case, you have the choice of either checking the receipt on the device or on the server. I guess there are pros and cons to each. Do you have code running on the server to support the app, or does the app just download files? If you have code running on the server you may prefer to extend that to do the checking.

What is your threat model? Are you aware of people actually cracking your app?

Should I continue using the verifyReceipt endpoint from the device?

What you're currently doing will continue to work, but it is not ideal as described above.

Should I plan to use the verifyReceipt endpoint from my server?

I wouldn't recommend that for new code as it's deprecated.

Should I plan to use the App Store Server API and App Store Server Notifications V2?

You could do that (though I don't personally know much about that).

Your other option is the validate the receipt on the server without communication with Apple.

There is a page titled "Choosing a receipt validation technique" here:

https://developer.apple.com/documentation/storekit/in-app_purchase/original_api_for_in-app_purchase/choosing_a_receipt_validation_technique

Thank you @endecotp for such useful feedback on my queries, it really means a lot to me.

@App Store Commerce Engineer Is there anything you can suggest about it? It would be very helpful.