- Home /
Google Play - IAP Purchase Server side receipt validation
Hi, turns out our in app purchase integration is hackable, some people have already racked up $900 worth of fake purchases so far! We're using Prime31 plugin for Unity and they recommend referring to the google docs for server-side receipt validation.
Trouble is this is the first time I'm doing this type of job and there doesn't seem to be any decent step-by-step guide or walk-through on google or anywhere else for that matter to set it up. If I manage it I might make one for laymen like myself.
Using the Prime31 plugin I have got so far as to receive a successful GooglePurchase object back to Unity.
From what I have understood, the .originalJson field of that object needs to be Sha1 hashed with the google play private key (possibly also with a unique identifier like the player's username) in Unity and then sent to the server for validation and a success/failed result returned back to Unity before the item is consumed. Does that sound like an accurate description of what's involved client side?
If so, what I'm having difficulty understanding now is what to do with this string on the server? What should constitute a valid result or an invalid result? Does the server need to call up google directly to compare the hashed string to something? Or does the server need its own copy of the private key to compare it with?
Does anyone have any insight into how people are actually hacking these purchases? Is it by reverse engineering the APK and discovering the private key? It would be helpful to know what we are trying to prevent in order to understand the apparent solution we are trying to implement.
Any info at all would be greatly appreciated. Thanks.
Delving further into this, for anyone interested, it appears that the most common type of hack for in-app-purchases is a "man-in-the-middle" attack where the client unwittingly calls a server that pretends to be Google, which receives the purchase request from the client (your app), and always returns a successful response, irrespective of whether or not any money was taken.
The reasoning therefore behind receipt validation, is to verify that the server the request was sent to was actually Google, as opposed to some dodgy IP made by the hacker.
The way we can verify this, is by using the GooglePlay Public $$anonymous$$ey, which is basically a long string constant randomly generated by Google when you register a new app that only Google, and the developer know about (find it in the google-play console under "Services & API"'s tab).
The presumption is that the "man-in-the-middle" (the hacker's dodgy server) doesn't know this key and, unlike Google, can not return it in its dodgy GooglePurchase response object.
So far from what I've understood google use this key (or possibly its private counterpart - something I'm still trying to understand) to encrypt/hash the GooglePurchase.signature field of the response in a way that the "man-in-the-middle" can not do.
Therefore the developer can be sure that the response came from Google by "validating" the signature field of the response. Validation is essentially = ensuring that the signature was encrypted in the expected manner that it should be if it made use of the public key.
I am still not sure why this can't be done locally, as in within the client (which also has a copy of the public key) and why the response needs to be sent off to a server for the validation to be done in PHP. This seems completely unnecessary to me, but I am sure I will find out in the co$$anonymous$$g days.
If anyone has any info that could be remotely useful to my effort I would really appreciate it.