I've been seeing several purchase attempts from my Phonegap iOS app with this odd transaction receipt, which appears to be invalid when I try to verify it at the itunes endpoint.
window.plugins.inAppPurchaseManager.onPurchased = function (transactionId, productId, receipt) {
// receipt is MC4wMDAwMDA= which base64 decodes to 0.000000
}
I'm suspecting a hack, but I want to verify that we aren't doing anything wrong.
This is using the official InAppPurchaseManager plugin from the phonegap-plugins repo on Cordova 1.7.
I'm not familiar with the plugin that you're using but I don't think you're doing anything wrong. There are several programs out there that forge receipts in an attempt to steal in-app purchases. Apple recommends validating receipts via your own server to make it more difficult for hackers and hacks to scam your products. You can read about Apple's receipt validation here and their recommended best practices here.
Receipts like MC4wMDAwMDA= or ones starting with Y29tLnVydXMuaWFwLj are common forged receipt signatures and will fail validation when submitted to Apple.
Related
in iOS with in-app purchases, it is necessary to verify receipts with subscriptions. is it necessary to verify receipts for consumables also?
No you don't need to verify receipts for consumables.
You don't need to verify receipts for subscriptions either. What's important here is that you can restore running subscriptions; but for that you can use purchase ID.
As always make 100% sure you've given the user what was paid for before telling iOS that the purchase was successful!
(There are all kinds of other considerations why you would like to keep purchase related information on a server, but that's not what you ask about.)
Necessary, no. Recommended, yes.
All purchases; consumables, un-consumables and subscriptions are susceptible to fraudulent attacks. Often though iap crackers or network spoofing. Validating the receipt can mitigate this problem.
You can validate the receipt locally in the app (see Validating Receipts Locally), though it is still susceptible to cracking.
The safest way to prevent fraud is to perform server-side validation by sending the receipt to your server then sending it on to Apple (see Validating Receipts With the App Store).
However, do not validate the receipt with the app store in the app itself. It's really easy to spoof the network request and return a positive (valid) result.
If you notice a large discrepancy between the actual purchases in your reports from Apple and your in-app purchase analytics (assuming you have that), you may want to invest in server-side validation, otherwise, if it's not a problem, don't worry about it.
We have a successful app on the iOS app store with in-app purchases. Every time a purchase is completed we send the receipt to our server, our server than checks the receipt with Apple's servers and logs apple's response(including whether the purchase was valid and that they come from our app in that same time and date).
We have quite a few users who use iap cracks that send us receipts that apple says are invalid. However we started now to see cheaters that have receipts that apple replies that are VALID. What is strange in these cheats, that when such a cheater user purchases in our app, he usually purchases all of the purchases with the exact same receipt.
Have you heard of such a way to 'fool' apple receipt validation?(to generate receipts that apple will say they are from our app in the time of the 'purchase')
Is there something we can do to find those cheaters in their 1st purchase (for the next purchases we can simply check times of the next receipts or make sure that our receipts are unique)
Thanks!
Is there something we can do to find those cheaters in their 1st purchase
Actually, if this is the same hack I've seen discussed as a proof of concept recently, the first purchase is legitimate. The "innovation" is in decoding that legitimate receipt and rejigging its IAP ID with a different one while the receipt overall still appears valid. So simply avoiding the duplicates is enough. Didn't think that one was anywhere near production-ready though, so this might be something different.
We also faced similar issue while developing a game of iOS app store where business model was based on In App Purchase only.
Initially we used to check with Apple Servers for the receipts directly from the device. But some hacker has created a hack for the users where they can install the DNS server certificate on their device which spoofs the response from Apple.
The way to do this is let web server check for the receipts from Apple directly with some kind of hashing or md5 check to make sure the response if from Apple.
here is a link which have a detailed information on this https://www.objc.io/issues/17-security/receipt-validation/
Hope this helps.
I followed Ray Wenderlich's tutorial to implement receipt validation in my app. The code connects to Apple's validation server directly from my app rather than going through my own server.
After I submitted my first binary to the AppStore, I tested my app and the in-app purchasing didn't work because I had switched it over from the sandbox URL to the production URL.
Will this also fail when they AppStore reviewers test it and therefore be rejected? I've read this post but I'm still very confused about whether that applies to me if I'm not using my own server.
The solution is quite simple and it was explained on session 308 of WWDC 2012 (the video is available for registered developers). The session was related to subscriptions but you can extend it for in app purchases.
What happens is that when you develop you hard code your app to validate the receipt with the sandbox. Then you send the app to review, you clearly hard coded your app to validate the receipt with the production server.
But nothing prevents you from doing the validation in two steps:
always validate the receipt with the production server first, this will apply for 99% of your app life. If the receipt is validated, you're done.
if previous validation failed, just validate the receipt with the sandbox server. This should cover your development needs and of course fake receipts will fail validation too.
By the way, and this is officially stated in the documentation ONLY for subscriptions, if you try to validate a sandbox receipt with the production server you will get a specific status code; there is another status code that covers the case of production receipt validated with the sandbox server. In all cases the two worlds, sandbox and production, are always separated.
Don't forget also that with iOS7 added a new safer way to manage receipt validation directly from the device: consider in fact that receipt validation directly from the client (that you don't fully control, e.g. with jailbroken devices) is less secure than receipt validation done through a server you control.
Always verify your receipt first with the production URL; proceed to verify with the sandbox URL if you receive a 21007 status code. Following this approach ensures that you do not have to switch between URLs while your application is being tested or reviewed in the sandbox or is live in the App Store.
Note: The 21007 status code indicates that this receipt is a sandbox receipt, but it was sent to the production service for verification.
There is no public API to call to distinguish the production and sandbox environments so that you can decide which server to use ahead of time. If you have implemented the recommended receipt validation process, the fix can be implemented at your server which contacts the StoreKit server. If the status code for the validation attempt is 21007, then try again at the sandbox server.
It could fail. I had an app with in app purchases (but not based on my server, straight apple code) that work in development but crashed once released by Apple. It crashed because I had not done all the proper steps in iTunes Connect.
The surprising thing was that the reviewers didn't catch this, presumably since they were also working in a sandboxed environment.
I'm not sure this helps you, hope it does.
I'm developing an app that uses newsstand for subscription purchase. Is it an Apple approval requirement that the IAP uses server receipt verification?
It is possible to implement IAP in apps without using a server to verify receipts. I'm just wondering whether it's possible to take this approach with newsstand apps (I understand that doing so loses some level of security, but it also reduces complexity).
The simple answer is that it's not an approval requirement, but as MSK says. it is recommended. I decided to go with server verification which is not too much trouble anyway. However, if you're interested, here's an example of verification being done from the app itself.
http://www.viggiosoft.com/blog/blog/2011/10/29/at-newsstand-and-subscriptions
I've got in-app purchases working just fine, and I'm going the server validation route. The server needs to know whether I'm in the sandbox or not, so for now I'm just sending it a "&sandbox=1" parameter. Of course when the full version of the app is out I won't be sending this parameter.
I'd rather not have this hardcoded in my app, as that will make testing difficult in the future, and it's one more (big) thing to remember to change before submitting builds to Apple.
Is there a way I can ask StoreKit if I am in the sandbox so I can then determine whether or not I need to send this parameter to my server? Alternatively, is there any other best practice for handling server validation?
Thinking about this more, should I just have the server always check the live system first, then the sandbox? If apple IDs are segregated between the live and sandbox systems then it wouldn't do any harm would it?
Thanks.
After a bit of digging I found this from Apple's Technical Note TN2259:
How do I verify my receipt (iOS)?
Always verify your receipt first with the production URL; proceed to verify with the sandbox URL if you receive a 21007 status code. Following this approach ensures that you do not have to switch between URLs while your application is being tested or reviewed in the sandbox or is live in the App Store.
So it looks like I should axe the &sandbox parameter completely and just do that. I really had to dig for this answer so I'm posting it here in hopes that someone else runs across it!
I encountered that very same problem, where my app was rejected because the "production" version of my app that I submitted was hardcoded to connect to a PHP script on my server that validates receipts with the real AppStore server (whereas my development build points to another PHP script that validates receipts with the sandbox server). However, after a few exchanges with Apple engineers, I found out that they use sandboxed user accounts to tests submitted applications, which explains why they got an error.
Instead of conditionally building my app to point to one script or the other, I will use a single script that tries the production server first and then falls back to the sandbox server if it receives the 21007 status code, as explained above!
Thanks a lot!
Always verify your receipt first with the production URL; proceed to verify with the sandbox URL if you receive a 21007 status code.
Unfortunately, the technical note fails to mention this is only valid for auto-renewing subscriptions!
As the In-App Purchase Programming Guide mentions below table 7-1:
Important The non-zero status codes here apply only when recovering information about a auto-renewable subscription. Do not use these status codes when testing responses for other kinds of products.
For non-renewing subscriptions, the production server does not return a status code, but a proper receipt.
In case you are forced to use non-renewing and implement your own subscription expiring logic, a possible solution is to send your app version along to your server, and keep track of which versions are in development at the moment, as such you can redirect to the sandbox.itunes server to verify receipts where appropriate, and mimic the x-minute expiring time of a subscription (as sandbox.itunes does for auto-renewing) for development on your server.