Issue
A user made a purchase in my app but Google has no trace of it in their records. I would like to know if the security of my app is compromised or if it's on the Google end which I doubt.
Context
I developed an hybrid app using the ionic framework (angular). The app supports in app billing with the help of that cordova plugin for Android which is open source: https://github.com/poiuytrez/AndroidInAppBilling
The app has been deployed on the Play Store minified and uglified.
The buying process calls the plugin that handles the transaction, and when the transaction is done (payment done by the user), the plugin receives a payload from Google.
inappbilling.buy(success, fail, productId)
Example Payload
{
"orderId":"12999763169054705758.1385463868367493",
"packageName":"com.example.myPackage",
"productId":"example_subscription",
"purchaseTime":1397590291362,
"purchaseState":0,
"purchaseToken":"ndglbpnjmbfccnaocnppjjfa.AO-J1Ozv857LtAk32HbtVNaK5BVnDm9sMyHFJkl-R_hJ7dCSVTazsnPGgnwNOajDm-Q3DvKEXLRWQXvucyW2rrEvAGr3wiG3KnMayn5yprqYCkMNhFl4KgZWt-4-b4Gr29_Lq8kcfKCkI57t5rUmFzTdj5fAdvX5KQ",
"receipt":"{...}",
"signature":"qs54SGHgjGSJHSKJHIU"
}
Then I send that payload to a REST API. The API is secured with a signed JWT token that is sent with each request. On the server side the JWT token is decoded to get the user id. Then I store the payload in the user entity.
Then I manually check the payload with node-iap. I get the following response which means that the payload is legit.
Actual Verification
{
receipt:{
kind:'androidpublisher#productPurchase',
purchaseTimeMillis:'1436002850700',
purchaseState:1,
consumptionState:1,
developerPayload:''
},
transactionId:'ofnjgihgpabbodngadeegagl.AO-J1OwBenqmX7tCt_XeW3bgDYMnxxxKqNi8x8Q_yuKsbDW5VFWm6WyDfbYAaCiyF2-BJFI4Sy6o2UGHwvPdY7X6qz0O_k64BBRYTot5W7z5bfpXQ391QbAhD0',
productId:'paid.pro',
platform:'google'
}
Hypothesis
Disclaimer: My security knowledge level is very low.
Let's say the user found the API end point to call if the purchase process succeed. He has the signed JWT token because it's stored in the local storage after login. He has to generate a payload and send it with the JWT token.
The generated payload seems valid when I checked it. How is it possible? Does he manage to get my private key?
No nobody get your private key. Your payload is not signed with a public/private key, only your token is signed with a private key. So whatever you send to your server with a valid token it will be accepted.