2015-4-3更新

1. 将原有分散的代码封装为通用库 ggpay,代码在: https://github.com/dantezhu/ggpay,也可以直接 pip install ggpay 进行安装,使用方法见 examples 的get_token。


最近在google play上线的应用内支付被人刷了,用户模拟发起了大量的支付请求,并且全部成功支付。搞得我最近茶饭不思。。今天总算是解决了,和大家分享一下。

我们客户端的支付实现步骤是:

1. app端调用google支付

2. 支付成功后,调用 自己服务器的发货接口,当然发货接口是做了签名校验的。

之所以在app端调用发货,是因为google貌似没有提供服务器端直接回调url的地方,所以才给了恶意用户模拟google返回的机会。

 

一开始我以为是我们自己的发货接口密钥被破解了,但是后来经过app上报,发现客户端是真实的走过了所有的google支付流程,即google的支付sdk真的返回了成功。

由于不清楚是因为google的密钥泄漏还是攻击者用别的方法实现,所以客户端这边已经没有办法确认是安全的了。

好在google是提供了查询订单的接口的: http://developer.android.com/google/play/billing/gp-purchase-status-api.html

实现的流程在文档中已经写的很清楚了,我这里就不赘述了。

判断的方法也很简单:

1. 判断是否购买成功

2. 判断返回 developerPayload 是否与传入的值一致。最好传入订单号,以防止重放攻击。

 

实现代码如下:

 

最后感慨一下,以前在腾讯的时候,安全问题有大帮人帮你一起查,所以根本感觉不到什么危险。现在只有自己了,所有的问题都要考虑到,而且一旦处理不好就可能是致命的。

暂无相关产品

22则回应给“google支付接口被刷以及解决方案”

  1. 李雪冰说道:

    敢问博主现在在哪里上班,还是自己出来做?

    [回复]

  2. 李振华说道:

    vimer您好, 我们也遇到这种问题, 请问一下refresh_token 这个token是从哪里来的呢?是支付返回的purchaseToken吗?

    [回复]

    phper08 回复:

    第一次获取access_token的时候得到,在后面获取access_token的时候不再返回refresh_token,所以要保存好,当然移除了应用授权之后再获取access_token也是可以得到refresh_token的,在https://security.google.com/settings/security/permissions 这里删除授权

    [回复]

  3. 李振华说道:

    可以跟您交流一下吗? 我们也是在服务器端做了校验, 但是发现有用户模拟了大量可以通过RAS校验的订单数据,所以现在也只能用googleplay查询订单的方式来做验证了。但我们用了service account的JWT方式,获取token的时候总是报400无效授权, 所以想用您这种方式试试

    [回复]

    朱念洋 回复:

    你好没问题哈,其实我代码都贴在文章里的,应该直接拿过去用就行啦

    [回复]

  4. wangying说道:

    你好,我按照上面的方法调用https://www.googleapis.com/androidpublisher/v1.1/applications/{packageName}/inapp/{productId}/purchases/{token} 这个的时候总是报 { “error”: { “errors”: [ { "domain": "global", "reason": "invalid", "message": "Invalid Value" } ], “code”: 400, “message”: “Invalid Value” }} 这个错误,这个订单的purchase_token 是客户端成功后返回的,请问怎么解呢?谢谢

    [回复]

  5. xiaoqiang说道:

    请问博主,初始化时的三个参数(client_id, client_secret, refresh_token)都传什么啊?没看明白这块,麻烦帮忙解答下吧,万分感谢!这是客户端收到的谷歌返回的两个对象IabResult result, Purchase purchasepublic class IabResult { int mResponse; String mMessage;}public class Purchase { String mOrderId; String mPackageName; String mSku; long mPurchaseTime; int mPurchaseState; String mDeveloperPayload; String mToken; String mOriginalJson; String mSignature;}

    [回复]

    xiaoqiang 回复:

    博主,我在google通过通过Create Client ID 得到了一组json数据,下面是这组数据所有的key['auth_uri', 'redirect_uris', 'client_email', 'client_id', 'token_uri', 'client_secret', 'auth_provider_x509_cert_url', 'javascript_origins', 'client_x509_cert_url']其中client_id, client_secret找到了,但是 refresh_token还是不清楚应该传什么啊

    [回复]

    朱念洋 回复:

    https://accounts.google.com/o/oauth2/token 通过这个接口兑换回来的

    [回复]

    裴星鑫 回复:

    是不是要客户端发起来获得?

    [回复]

    朱念洋 回复:

    参见: https://developers.google.com/accounts/docs/OAuth2InstalledApp#formingtheurl, 里面有个 grant_type=authorization_code 的部分就是

    [回复]

    xiaoqiang 回复:

    请问博主,这个里面的code是怎么得到的啊,我的数据里面没有找到code=4/v6xr77ewYqhvHSyW6UJ1w7jKwAzu&client_id=8819981768.apps.googleusercontent.com&client_secret=your_client_secret&redirect_uri=https://oauth2-login-demo.appspot.com/code&grant_type=authorization_code

    [回复]

  6. xiaoqiang说道:

    感谢博主,这个校验我搞清楚是什么原理了,现在在做的是一个手机游戏在google play的支付校验,现在需要对方提供client_id, client_secret和redirect_uri,但是对方说没有这些。。。能问下博主,这些参数应该在哪里可以找到么,拜谢了!

    [回复]

  7. 肥皂说道:

    博主,获取refresh_token的时候需要用户登陆授权么~还是怎么样可以通过发消息就获得呢~求解~

    [回复]

  8. 郭明说道:

    refresh_token就是code吗?这个是客户端去获得还是服务器去获得?

    [回复]

    朱念洋 回复:

    用开发者帐号登录授权,就可以拿到对应的code和refreshcode

    [回复]

    郭明 回复:

    code每次得到的值都不一样啊然后再获得refreshcode时,总是返回{error,invialid_request}

    [回复]

  9. 郭明说道:

    code需要重定向得到,然后用code得到refresh_token。。。是这样吧但code怎么能在游戏逻辑里去跟googleplay请求呢?

    [回复]

  10. 郭明说道:

    The browser will be redirected to your redirect URI with a code parameter, which will look similar to 4/eWdxD7b-YSQ5CNNb-c2iI83KQx19.wp6198ti5Zc7dJ3UXOl0T3aRLxQmbwI.这个code明显是通过浏览器来获取的,您是怎么处理的能完整的说下吗?多谢~

    [回复]

  11. 牵着的x右手说道:

    google api 使用 https://accounts.google.com/o/oauth2/token 已经获取不到 refresh_token 了?就是说你写的那段代码没用了是吗?只能通过异步验证:每天手工登录生成access_token,然后批量检查昨日订单,有问题的用户进行封号处理?如何手工登录生成access_token?又如何批量检查昨日订单

    [回复]

    朱念洋 回复:

    ggpay中readme有写

    [回复]

  12. lidashuang说道:

    refresh_token 不会过期吧

    [回复]

发表评论