How to validate restored purchases?

Started by
3 comments, last by SimonForsman 9 years, 3 months ago

Hi guys,

I have implemented server side receipt validation and it is working pretty well so far. Here are the general steps I take for new purchases:

1) On device: get receipt from Google/Apple, send it to my server

2) On server: parse the data

  • For Apple: send to Apple servers to validate
  • For Google: verify receipt data against signature

3) If everything checks out, check against my database to see if the transaction id has been used before. If it exists in my DB then someone is trying to reuse an old receipt. If it doesn't exist, then save it.

4) Send a response back to my device and unlock content accordingly

The problem that I'm facing, is what to do when restoring purchases? I don't have an Apple device to test with yet, but on Google, the receipt that I get back for a restore is identical to the original purchase receipt. So when I do the transaction id check on my database it will fail. Theoretically, somebody could make a valid purchase once, and then pass around that valid receipt with an IAP cracker to trick my server into restoring features. (I know you can't stop hackers but I want to at least make it difficult)

Here are the solutions I can think of:

  1. Tie transaction ids to user accounts. This might be the best solution but it would force me to force everyone to create an account in order to make purchases. Right now it's a single player game so creating an account would seem pointless to users, and I want to make it easy to make purchases. Plus having user account functionality is a whole other beast entirely... I don't really have the time to implement that now.
  2. Tie transaction ids to unique device ids. Easy to implement but this means that a user would never be able to restore their purchases on a new or different device.

I'm really not sure what to do. I've searched high and low but people only talk about validating new receipts. Any help is greatly appreciated.

Advertisement


Theoretically, somebody could make a valid purchase once, and then pass around that valid receipt with an IAP cracker to trick my server into restoring features.

Yes, the bad guys can pass around valid tokens. The bad guys can also use keygen programs. The bad guys can hack your executable. The bad guys will be bad guys.

This is a case where you don't worry so much about what bad guys might potentially do. If you check the IAP result and the server says it was purchased (not cancelled or refunded) then let them play. Don't try to lock it down any more than the store providers already do.

You need to chose which of these you will provide:

* Paying customers get good experience, bad guys play without paying.

* Paying customers get a bad experience, bad guys play without paying.

If I purchased your game on the store, then I go to play on another device and it comes back as not authorized, I'm going to complain about it and other customers will see it.

A simple solution might be to just cap the number of times the server will validate the receipt without intervention from you to some reasonable number -- say 5 or 10 times. That way, if a group posts a receipt in order to attack you, only the first few will succeed; thereafter the crack will fail and it will likely be downvoted/forgotten about on whatever site it was posted. Now, its still possible that a user might legitimately want to install your app on that number of devices over the lifetime of the app, so when the server finds the number of validations have been exceeded, pop up a messagebox with instructions (or better yet, a template) for contacting you to lodge a support ticket to unstick their validation. That gives you a chance to intervene in mass piracy, while not costing you too much developer effort, or the customer too much trouble -- they write you an email, you make sure their story checks out, and you reset the validation counter in your database -- if you see a thousand requests against that receipt, you know its been compromised, and can react accordingly. This incurs some work on you to intervene, but the difference between (large-scale) piracy and legitimate users will be obvious -- if your game should ever be so popular that the volume of this work overwhelms you, you'll probably be wealthy enough to hire the help.

A skilled cracker will be able to side-step all of this, but IMO the above describes about the right level of effort to go to in stemming the tide of casual piracy.

In another approach, even if your game has no multi-player content, if you can provide *some* kind of service (friends, leaderboards, "cloud" saves, simple online inspection of their character) to online account holders, that can still incentivise them into creating an account and another fringe benefit might be that it simplifies this whole validation business by gaining you an account to tie them to.

throw table_exception("(? ???)? ? ???");

@frob: Thanks, i agree with everything you say. But I'm still curious if anybody has some viable solutions that allow for good user experience while curbing rampant piracy. I just find it odd that there are tons of articles and good solutions for validating new receipts, but a lack of good advice for validating restored receipts. Honestly, if Google just included a unique field that would differentiate between new and restored this would be non-issue.


@Ravyne: I like your idea about keeping a count. In fact, it occurred to me right after posting that I could do something like this. Rampant piracy is exactly what I'm trying to stop. I'm ok with the fact that some will fall through the cracks.

One question though, what happens ifa legitimate user spams the restore button? I suppose I could check that the purchase is not active on their device first before checking with my server.


Thanks for all your help! If anyone has other ideas I'm all ears.

A simple solution might be to just cap the number of times the server will validate the receipt without intervention from you to some reasonable number -- say 5 or 10 times. That way, if a group posts a receipt in order to attack you, only the first few will succeed; thereafter the crack will fail and it will likely be downvoted/forgotten about on whatever site it was posted. Now, its still possible that a user might legitimately want to install your app on that number of devices over the lifetime of the app, so when the server finds the number of validations have been exceeded, pop up a messagebox with instructions (or better yet, a template) for contacting you to lodge a support ticket to unstick their validation. That gives you a chance to intervene in mass piracy, while not costing you too much developer effort, or the customer too much trouble -- they write you an email, you make sure their story checks out, and you reset the validation counter in your database -- if you see a thousand requests against that receipt, you know its been compromised, and can react accordingly. This incurs some work on you to intervene, but the difference between (large-scale) piracy and legitimate users will be obvious -- if your game should ever be so popular that the volume of this work overwhelms you, you'll probably be wealthy enough to hire the help.

A skilled cracker will be able to side-step all of this, but IMO the above describes about the right level of effort to go to in stemming the tide of casual piracy.

In another approach, even if your game has no multi-player content, if you can provide *some* kind of service (friends, leaderboards, "cloud" saves, simple online inspection of their character) to online account holders, that can still incentivise them into creating an account and another fringe benefit might be that it simplifies this whole validation business by gaining you an account to tie them to.

I would add a time limit to the restorations aswell, a limit of lets say 5 restorations in a 90 day period is plenty for a legitimate user but pirates will hit that limit almost immediatly, if you also check the geographic location of the users after the limit has been reached you can detect quite easiliy if a reciept has been shared publicly (if you are getting restoration requests from several countries using the same reciept at pretty much the same time you can blacklist it permanently)

[size="1"]I don't suffer from insanity, I'm enjoying every minute of it.
The voices in my head may not be real, but they have some good ideas!

This topic is closed to new replies.

Advertisement