您的位置:首页 > 编程语言 > Go语言

google支付接口被刷以及解决方案

2015-01-06 15:28 357 查看
http://www.vimer.cn/2014/04/google支付接口被刷以及解决方案.html

最近在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 是否与传入的值一致。最好传入订单号,以防止重放攻击。

实现代码如下:

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106# -*- coding: utf-8 -*- import requestsimport datetime from .vals import logger class GooglePurchaseChecker(object): """ google的支付查询 """ client_id = None client_secret = None refresh_token = None access_token = None access_token_create_time = None access_token_expire_time = None def __init__(self, client_id, client_secret, refresh_token): self.client_id = client_id self.client_secret = client_secret self.refresh_token = refresh_token def get_new_access_token(self): """ 通过refresh_token获取access token """ base_url = 'https://accounts.google.com/o/oauth2/token' data = dict( grant_type='refresh_token', client_id=self.client_id, client_secret=self.client_secret, refresh_token=self.refresh_token, ) try: rsp = requests.post(base_url, data=data) jdata = rsp.json() if 'access_token' in jdata: self.access_token = jdata['access_token'] self.access_token_create_time = datetime.datetime.now() self.access_token_expire_time = self.access_token_create_time + datetime.timedelta( seconds=jdata['expires_in'] * 2 / 3 ) return True else: logger.error('no access_token: %s', rsp) return False except: logger.error('fail', exc_info=True) return False def should_get_new_access_token(self): """ 判断是否要重新获取access_token """ if not self.access_token: return True now = datetime.datetime.now() if now >= self.access_token_expire_time: return True return False def check_purchase(self, bill_id, package_name, product_id, purchase_token): """ 判断是否合法 """ logger.error('purchase check start.bill_id: %s', bill_id) if self.should_get_new_access_token(): if not self.get_new_access_token(): # 如果没有成功获取到access_token,也先认为成功吧 logger.error('get_new_access_token fail. bill_id:%s', bill_id) return -1 url_tpl = 'https://www.googleapis.com/androidpublisher/v1.1/applications/{packageName}/inapp/{productId}/purchases/{token}' url = url_tpl.format( packageName=package_name, productId=product_id, token=purchase_token, ) rsp = requests.get(url, params=dict( access_token=self.access_token, )) jdata = rsp.json() if 'purchaseState' not in jdata: logger.error('purchase invalid.bill_id: %s jdata: %s', bill_id, jdata) return -2 if jdata['purchaseState'] == 0 and jdata['developerPayload'] == 'DeveloperPayloadITEM%s' % bill_id: logger.error('purchase valid.bill_id: %s jdata: %s', bill_id, jdata) return 0 logger.error('purchase invalid.bill_id: %s jdata: %s', bill_id, jdata) return -3
1

最后感慨一下,以前在腾讯的时候,安全问题有大帮人帮你一起查,所以根本感觉不到什么危险。现在只有自己了,所有的问题都要考虑到,而且一旦处理不好就可能是致命的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: