Validating iOS in-app non-subscription purchases


#1

We just launched the iOS version of our app that includes consumable non-subscription in-app purchases. The first day live we already had fake in-app purchases from hacked iOS devices. Juce does not provide a means to get the signed receipt data for an in-app purchase that can be sent to our server to then be validated with Apple’s server, as Apple outlines here:

https://developer.apple.com/library/archive/releasenotes/General/ValidateAppStoreReceipt/Chapters/ValidateRemotely.html

So I made some minor changes to the in-app purchasing code in order to get the signed receipt data sent to our listener via the productPurchaseFinished() callback.

In juce/juce_product_unlocking/in_app_purchases/juce_InAppPurchases.h I added the purchaseReceipt to the Purchase struct (inserted at line 88):

    /** CNS: for iOS only: this is the purchase receipt that should be sent to the application's server for verifying the purchase with Apple's server. */
    String purchaseReceipt;

In juce/juce_product_unlocking/native/juce_ios_InAppPurchases.cpp I added code in processTransactionFinish() to get and set the purchase receipt (starting at line 431):

    // CNS: get the purchase receipt to send along with the other purchase data
    String purchaseReceipt;
    if (success)
    {
        auto* receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];

        if (auto* receiptData = [NSData dataWithContentsOfURL: receiptURL])
        {
            NSString* receiptString = [receiptData base64EncodedStringWithOptions:0];
            purchaseReceipt = nsStringToJuce(receiptString);
        }
    }

    // CNS: added the purchaseReceipt to the Purchase object
    Purchase purchase { orderId, productId, packageName, purchaseTime, {}, purchaseReceipt };

Now our listener callback gets the signed receipt data, passes it to our server, and our server does real-time validation with Apple’s server. This validation has to come from our server since a connection from the client device to Apple cannot be trusted.


#2

which OS were you supporting? is iOS12 and 11 jailbroken?


#3

We support iOS 11 and up. We log all invalid purchase attempts. The offending users have devices with iOS versions of 11.1, 11.2.6, 11.3.1 and 11.4.1.