Android 应用内购买验证
Android InApp purchase verification
我有一个移动应用,其中包含一些用户可以购买的应用内商品。一旦用户购买了一些 inapp 产品,应用程序就会将 JSON 收据发送到我的服务器,以便根据我的 Google 开发人员 public 密钥(存储在服务器中)进行在线验证。
应用程序将签名和数据(又名收据)发送到服务器:
$signature = 'E2dxlmSe0d45eJpN4FKSUxNPYXM5A1zohpVL60Hd+5jd43j4YMhBlVRLwFeDaBKZnkJ39rYYesWoOu8Z5ysczAIiQO7Myko7UJYVYKvB5GqM8a0iEDjCdCpSRSqLUmaEHKwUJFfjcgw1K5L2gM/m3u8l7Jy25IB+HFVIikO50jiy8SMRh7S+s6PgEAXqG6K6vTpuTC5ECweuQ45VTdb0jNyWOzEW/I1nA5fAB/mmp5j3B6k7nN81NMh/3oUJHba/wWGlbkWtItmDU6/jMdpd1CVViNBhKe0ktwnSRz3XF607/AfZM6JteOKhC6TquWhVNuWpKJWdJbP7Q+RVS0YKog==';
$data = '{"orderId":"GPA.xxxx-xxxx-xxxx-xxxxx","packageName":"xxx.xxx.xxx","productId":"xxx","purchaseTime":1508881024560,"purchaseState":0,"purchaseToken":"didpmjkaldaddakgfabdohdj.AO-J1Ozqb8hZAa-_FLd-sQJgXhwruU3tVEYU0sqhlgXHb8I9wI35xDeQFgFI0Zpoaurw4Ry7zahymvge1U0WlEqqvvAKvwAo0Wk1MtawzAiqVdy2RTvwFGo"}';
这是我用于签名验证的 PHP 代码:
$pkey = "...";
$apkey = "-----BEGIN PUBLIC KEY-----\n".chunk_split($pkey, 64, "\n")."-----END PUBLIC KEY-----";
$pubkeyid = openssl_get_publickey($apkey);
$ok = openssl_verify($data, $signature, $pubkeyid);
openssl_free_key($pubkeyid);
echo $ok;
当然是行不通的。 OpenSSL 函数 returns 0(而不是 1 表示 OK)。根据在线文档 https://developer.android.com/google/play/billing/billing_integrate.html
我必须检查的是 INAPP_PURCHASE_DATA
,即 receipt
。这是来自文档的示例:
'{
"orderId":"GPA.1234-5678-9012-34567",
"packageName":"com.example.app",
"productId":"exampleSku",
"purchaseTime":1345678900000,
"purchaseState":0,
"developerPayload":"bGoa+V7g/yqDXvKRqq+JTFn4uQZbPiQJo4pf9RzJ",
"purchaseToken":"opaque-token-up-to-1000-characters"
}'
这正是我的应用发送的内容。现在,由于签名验证需要完美的数据,我应该如何 "send" 这样的字符串到 OpenSSL 函数?在文档上,数据有换行符和缩进,我的是完全相同的 JSON 结构,但记录为没有换行符和缩进的纯字符串。它是相同的数据 JSON-wise,但从加密签名验证的角度来看非常不同。有人可以解释一下该怎么做吗?
解决了问题:
data
必须是没有缩进和换行的纯字符串
- 签名必须经过 base64 解码才能传递给 OpenSSL 函数
所以不是这个:
$ok = openssl_verify($data, $signature, $pubkeyid);
我必须这样做:
$ok = openssl_verify($data, base64_decode($signature), $pubkeyid);
我有一个移动应用,其中包含一些用户可以购买的应用内商品。一旦用户购买了一些 inapp 产品,应用程序就会将 JSON 收据发送到我的服务器,以便根据我的 Google 开发人员 public 密钥(存储在服务器中)进行在线验证。
应用程序将签名和数据(又名收据)发送到服务器:
$signature = 'E2dxlmSe0d45eJpN4FKSUxNPYXM5A1zohpVL60Hd+5jd43j4YMhBlVRLwFeDaBKZnkJ39rYYesWoOu8Z5ysczAIiQO7Myko7UJYVYKvB5GqM8a0iEDjCdCpSRSqLUmaEHKwUJFfjcgw1K5L2gM/m3u8l7Jy25IB+HFVIikO50jiy8SMRh7S+s6PgEAXqG6K6vTpuTC5ECweuQ45VTdb0jNyWOzEW/I1nA5fAB/mmp5j3B6k7nN81NMh/3oUJHba/wWGlbkWtItmDU6/jMdpd1CVViNBhKe0ktwnSRz3XF607/AfZM6JteOKhC6TquWhVNuWpKJWdJbP7Q+RVS0YKog==';
$data = '{"orderId":"GPA.xxxx-xxxx-xxxx-xxxxx","packageName":"xxx.xxx.xxx","productId":"xxx","purchaseTime":1508881024560,"purchaseState":0,"purchaseToken":"didpmjkaldaddakgfabdohdj.AO-J1Ozqb8hZAa-_FLd-sQJgXhwruU3tVEYU0sqhlgXHb8I9wI35xDeQFgFI0Zpoaurw4Ry7zahymvge1U0WlEqqvvAKvwAo0Wk1MtawzAiqVdy2RTvwFGo"}';
这是我用于签名验证的 PHP 代码:
$pkey = "...";
$apkey = "-----BEGIN PUBLIC KEY-----\n".chunk_split($pkey, 64, "\n")."-----END PUBLIC KEY-----";
$pubkeyid = openssl_get_publickey($apkey);
$ok = openssl_verify($data, $signature, $pubkeyid);
openssl_free_key($pubkeyid);
echo $ok;
当然是行不通的。 OpenSSL 函数 returns 0(而不是 1 表示 OK)。根据在线文档 https://developer.android.com/google/play/billing/billing_integrate.html
我必须检查的是 INAPP_PURCHASE_DATA
,即 receipt
。这是来自文档的示例:
'{
"orderId":"GPA.1234-5678-9012-34567",
"packageName":"com.example.app",
"productId":"exampleSku",
"purchaseTime":1345678900000,
"purchaseState":0,
"developerPayload":"bGoa+V7g/yqDXvKRqq+JTFn4uQZbPiQJo4pf9RzJ",
"purchaseToken":"opaque-token-up-to-1000-characters"
}'
这正是我的应用发送的内容。现在,由于签名验证需要完美的数据,我应该如何 "send" 这样的字符串到 OpenSSL 函数?在文档上,数据有换行符和缩进,我的是完全相同的 JSON 结构,但记录为没有换行符和缩进的纯字符串。它是相同的数据 JSON-wise,但从加密签名验证的角度来看非常不同。有人可以解释一下该怎么做吗?
解决了问题:
data
必须是没有缩进和换行的纯字符串- 签名必须经过 base64 解码才能传递给 OpenSSL 函数
所以不是这个:
$ok = openssl_verify($data, $signature, $pubkeyid);
我必须这样做:
$ok = openssl_verify($data, base64_decode($signature), $pubkeyid);