How do I protect in app purchase content? [duplicate] - ios

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Secure way to unlock full version via In-App Purchase
What is the recommended way to protect content which has been downloaded following an in-app purchase from being copied to another device? The typical process seems to be copy the content to the 'Application Support' folder and set a flag in the NSUserDefaults. Both of these could be updated by someone accessing the iOS device via Finder or similar. If I store the transaction receipt, that could also be copied across.
I can potentially use the restoreTransactions functionality to validate when the device is online, but that requires the user to enter their password, so it isn't a silent background check and obviously wouldn't work if the device is offline.
I'm tempted to use a device ID to tie the content to the device when it is downloaded, but Apple advise against using this.
Am I missing something?

As you mentioned saving it the state in the NSUserDefaults is easily edited, but save the state in the KeyChain makes it harder for the user to change the flag state for a download.
I save all my IAP download state in the KeyChain, there by make sure that you can't just set the key to true in NSUserDefaults.
In a game we developed we also check server side if the user has bought the game item (also including the recept checking).
In a reader we made the PDF is password protected, via a sort of random code based on the name plus some secret stuff ;)
My guesses are that this should make you are less easy to crack, just keep in mind that you can't also keep a head of the crackers. But you can definitely slow them down.

Related

iOS in-app purchase for a paid app

I created an app which is a paid app. Now I want to make it free so more user can download the app and use in app purchase to limit some features. But some user already paid to buy my app. How can I implement in app purchase for new user at the same time keep full feature access to old user?
If you connect to your server for registering user info, you can always create an API which executes on app launch to verify that user is full access user or not.
But I am afraid your case is not the above one.
In that case you would require to sync your data (some encrypted key in this context) with iCloud and when application is launched you can verify the type of user.
Using data in iCloud is more safer as compared to keychain as it covers device format scenario. But definitely not foolproof.
Other solution can be using Apple Purchase Receipt to verify the version of previous purchase. But this is only supported since iOS7.
Checkout some opensource libs to understand the parsing of receipts:
https://github.com/rmaddy/VerifyStoreReceiptiOS
So combining multiple strategies is the only answer for your question.
You can do this by reading the App Store receipt. The receipt contains the version number and date of the original purchase.
There are two main caveats: first, this only works on iOS 7 and above. Secondly, Apple don't include code for parsing the receipt (so it's not too easy for users to hack I understand). There are, however, onen source libraries, though using a common one will be less secure.
There are no perfect solutions to this scenario.
Suggestion 1:
Roll out one last paid update. In this update, use keychain to store those IAP flags. Then in the free version, check for these flags in keychain. This will work even if app was deleted and reinstalled with the free version later. But it will not work if the device is being reset completely whether due to some iOS version updates or user's unless a backup and restore also is involved.
Suggestion 2:
Not quite a suggestion. But I have seen similar apps on AppStore have just rollout free version. Then app incurred bad reviews from those previous users!
This is a simple example, but if you're working with a database on a server (not on the phone itself), can't you use a boolean for each feature you plan on selling, and just set that boolean to true for all users currently in the database. This is assuming true means they've bought the feature, and false means they haven't bought it.
You could run this query once after releasing your updated app, and then every user after that would have a default value of false for these features you're selling.

How to ban an iOS user?

A while ago, I got banned from an iOS app. Not a user ID ban, but it seems to have been a device ban. Even if I delete and reinstall the app and try to make a new account, it would automatically get banned. My question is, how are they doing this? What are all the possible ways to ban a device that is persistent even after deleting and re-installing the app?
It is not possible to access UDID anymore, so there's that. And I don't think iOS allows them to view iTunes account, so that's not possible. Are they perhaps storing anything in the keychain? From what I know, some things in the keychain don't get removed even if the app is uninstalled.
I'd like to implement something like this in my app, so I want to know all the possible methods, with pros and cons for each.
When the app is uninstalled, all data goes with it. So writing anything to disk isn't going to work.
You can store something in the keychain, although users can edit the keychain if they sync it to a mac. That makes it pretty insecure.
The best option is to store it off the device, in iCloud. I'd go with key/value storage: https://developer.apple.com/library/mac/documentation/General/Conceptual/iCloudDesignGuide/Chapters/DesigningForKey-ValueDataIniCloud.html
Another option you could choose is Apple's replacement for reading the UDID which is to grab the advertising identifier. However it is possible for users to block this in Settings and your app could theoretically be kicked out of the store if it's used for something other than the intended purpose. I don't think it's actively policed, but still probably not a good idea to use it.
A belts and suspenders option would be to do everything:
save it to disk (in application support)
save it to key value storage in icloud
save it to keychain
use the advertising identifier to and send it to a remote server that you control (personally I'd skip this to avoid having the app banned from the store)
However... I'm not sure if Apple allows users to be banned. You might well be violating the developer rules by doing so. Especially the last one, which goes something like "this list is incomplete and constantly changing, your app might cause us to add a new rule to the list".
If it's a paid app or has in app purchases I'm pretty sure they would issue refunds to any customer who complains, and they'd probably follow the refund up with kicking your app out of the store.
Were I tasked to implement something like this, I would do exactly what you suspect: generate a simple random token, keep it in the keychain, and include it in API requests.
Nothing in the iOS keychain is removed when the app is uninstalled. I don't actually know of a good way to manually remove stuff from it.

Where to store a piece of important data (away from users) that will be backed up by itunes

I am currently making an app and there is an important piece of information I need to store. The user can make a one time in-app purchase.
My question is, what is the apple recommended or approved method for storing this?
No. 1 is most important to me. For example imagine the user can purchase 10 lives. After his purchase he will use some of them so imagine he now has a balance of 5. Where should this number be stored.
The issues or thoughts or random ideas I have as a result of reading things are;
if its saved in a simple file then a jailbreaker can just go in an
edit the file.
if its saved in an encrypted file I think I have extra issues with my
app/Apple/certain countries because I am using encryption.
what happens when the user accidentally removes the app. He cannot
restore his purchases as its a one time purchase
should I be and how should this important piece of information be
backed up on a sync
how do I ensure this information is saved as part of a backup.
I am not sure there is one answer to this problem. In my case I save the information in the keychain. Other iOS SDKs such as Amazon's or Facebook's do the same thing as far as I can see.

Detect first time install in iOS NOT NSUserDefaults

How it works - The app is a subscription to a service that works cross platform. On the iphone the initial purchase will get you 30 days of full functionality then after 30 days you can't do ceirtain things until you buy a subscription with an in app purchase.
What I need - I need to know if it was the first run so that I can add the users info to the database. Or because it is cross platform they may have already paid for a subscription so I need to add 30 days to the user's already existing subscription.
What I am doing now - Currently I am storing the identifierForVendor in the remote database and in NSUserDefaults there is a bool checked to see 1. if it is the first run and 2. if it is the first run to allow the user to add themselves to the database for a 30 day full use, or to add 30 days to their existing subscription.
The Problem - The problem is that if the user deletes the app then reinstalls it the NSUserDefaults will be deleted too, and the identifierForVendor will change and that will allow the user to add another 30 days to their subscription for free just by deleting and reinstalling the app.
Ideal Solution I originally wanted to do a subscription for the app, but I didn't know how to check the receipt when the app is originally purchased and insert the user into the remote database. Also I don't really know how to setup a subscription that isn't an In App Purchase. I also thought about making the app free and then they can use the In App Purchase to buy the service but the app is useless without being able to connect to the remote server to build up data in the first place.
Bottom Line I would like to do one of the following
Make the subscription on the first purchase (I need to be able to detect if the purchase is valid so I can enter the user info into the remote database)
Make the app free then use In App Purchase to add subscription (Is it acceptable to have a free app that won't do anything until you subscribe?)
Leave it the way it is now (but find a more permanent solution to the identifierForVendor, and the identifierForAdvertising won't work either because it can be turned off)
This will help you so much. Basically it's a wrapper for Keychain that is patterned after NSUserDefaults. It heled me a lot. Storing things in the Keychain makes them stay past app reinstalls.
https://github.com/carlbrown/PDKeychainBindingsController
This project is intended to make using the Mac OSX and iOS Keychains
as easy as NSUserDefaults.
It is a KVO-compliant Cocoa wrapper around the Mac OSX and iOS
Keychains, and the model for this wrapper is NSUserDefaults, so the
intent is that for the common cases you would normally want to call:
[NSUserDefaultsController sharedUserDefaultsController] You should be
able to call
[PDKeychainBindingsController sharedKeychainBindingsController] And
for the common cases you normally would have called:
[NSUserDefaults standardUserDefaults] You should be able to call
[PDKeychainBindings sharedKeychainBindings]

Saving information about previous purchased items in iOS

I am working on an app that has a number of in app store purchase items that will enable certain functionality.
After each item is purchased, I would need to remember it (of course). I would also like to persist this information in iCloud in case the app is deleted or is installed on another device.
What is the best data structure to be used?
Can user defaults database be used for this?
What is important is that the user will not have access to change those values and enable by themselves the paid functionality.
Can user defaults database be used for this?
It can, but it's not the best idea to do so, since
What is important is that the user will not have access to change those values and enable by themselves the paid functionality.
and NSUserDefaults stores its contents as binary or plaintext property lists. Easily changeable on a jailbroken device. (Also changeable on a non-jailbroken one by modifying the iTunes backup files).
What you could do is either store them in the keychain, although the keychain is not really designed for this (and it can also be dumped on a jailbroken device using Ptoomey3's awesome Kaychain-Dumper tool), or better store it remotely on your server and let your server check what the user has purchased.
Of course, if it's not only the server that does the check, so for example you don't only send or don't send content based on purchases, but you also use this check for performing actions within your app, then it also can be hacked (google "MobileSubstrate cheat DoodleJump" for a nice example).
All in all: there's no perfectly secure system.
I use the KeychainItemWrapper class to store a flag in the keychain. The nice thing is, so far, is that the keychain survives an app deletion. IF the user then reinstalls the same app on the same device, the keychain data is still there.
There is no need to use iCloud. If the user installs your app on another device, you just need to provide a "Restore Purchases" button in your app. Then you call the Store Kit APIs to restore existing purchases. The "In-App Purchasing Programming Guide" covers how to do this.
This same functionality will allow a user to restore their purchases even if the flags in the keychain are lost.

Resources