Mac App Store Receipt Validation

When you develop a Mac app, particularly paid app, it is important to ensure that users install genuine copies of your app via the right channel. Apps distributed outside of the Mac App Store achieve this by issuing Licenses to users which they need to enter into the app before they can start using it. Apps distributed via the Mac App Store achieve this using Mac App Store receipt validation.

Every app that is downloaded from the Mac App Store is provided a receipt that resides in the app bundle at /Contents/_MASReceipt/receipt. The receipt is cryptographically signed ensuring that only Apple can create it. Developers are required to write code to validate the receipt which guarantees that the copy of the app is valid and installed via the Mac App Store. Without this check by developers, apps can be downloaded once and passed around to other users bypassing the Mac App Store. Recently, I integrated receipt validation in my Mac App. This post attempts to summarize the knowledge I acquired in the process.

Receipt validation can be done in two ways

  1. Validating with the Mac App Store: From the app, you can pass the installed receipt to your server which can perform the validation by communicating with Apple servers and notify the app about the validation result.
  2. Validating locally in the app: You can write the receipt validation code locally in the application code.

This post only covers validating receipts locally. For validating receipts with the Mac App Store, check this. It is recommended by Apple that receipt validation be performed as soon as the app is launched. The validation code should be added to the main() function before NSApplicationMain() call.

Validation Steps In Order

  1. Locate the receipt and verify that it is properly signed by Apple.
  2. Verify that the bundle identifier, version identifier strings in the receipt match the CFBundleIdentifier, CFBundleShortVersionString values respectively in the Info.plist file.
  3. Compute the hash of the GUID and verify that it matches the hash in the receipt.
  4. Note: The GUID is uniquely tied to the hardware on which the app is originally installed from the Mac App Store ensuring that copied apps don’t work due to GUID mismatch.

If all of the above steps pass, validation succeeds.

Handling Validation Failure

Sometimes it may happen that a valid install fails to write the Mac App Store receipt to the app bundle resulting in receipt validation failure when the app runs. In such cases, you should call exit with a status of 173. This exit status notifies the system that your application has determined that its receipt is invalid. At this point, the system attempts to obtain a valid receipt and may prompt for the user’s iTunes credentials.

The system relaunches the application if it successfully obtains a valid receipt. Otherwise it displays an error message to the user explaining the problem. You should not display any error message to the user on validation failure because this duty is delegated to the system. The system is responsible for trying to obtain a valid receipt or informing the user that the receipt is not valid.

Things To Remember

  • Don’t Localize Your Version Number

    If your application is localized, the CFBundleShortVersionString key should not appear in any of your application’s InfoPlist.strings files. The unlocalized value from your Info.plist file is stored in the receipt. Attempting to localize the value for this key can cause receipt validation to fail.

  • Protect Your Validation Check
    1. Inline the code for cryptographic checks instead of using the APIs provided by the system.
    2. Avoid simple code constructions that provide a trivial target for patching the application binary. For example, avoid writing code like
      if (failedValidation) {
              exit(173);
      }
          
    3. Use code obfuscation to avoid reverse engineering.
    4. Ensure that even if the exit function fails to terminate your application, your application stops running. You may use abort().

Testing Receipt Validation During Development Phase

In order to test your Mac app during the development phase, you need a valid receipt so that your application launches. To set this up, do the following

  1. Make sure you have Internet access so you can connect to Apple’s servers.
  2. Create a test user in iTunesConnect > Manage Users section.
  3. Launch your application by double-clicking on it.
  4. Your application fails to validate its receipt because there is no receipt present and exits with a status of 173.
  5. The system interprets the exit status and attempts to obtain a valid receipt by prompting you to enter your iTunes credentials. You should provide the test user’s (step 2) details here.
  6. Assuming your application signing certificate is valid, the system installs a valid receipt for the application.
  7. The system relaunches your application, and your application successfully validates the receipt.

Receipt validation is a crucial step in Mac app development process and I hope this post makes implementing it easier for someone. Here are some libraries to get you started in the right direction. GOOD LUCK AND GOOD LIFE!!!

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s