通用技术 关于支付、关于安全的一些总结 (GOOGLE, APPLE, PAYPAL)

CaliforniaDream · 2017年07月14日 · 最后由 ata360 回复于 2019年02月12日 · 6749 次阅读
本帖已被设为精华帖!

来论坛已久,第一次发帖回馈社会😀
看到有些同学对于支付的测试比较迷茫,把我之前的经验总结了一下
希望能有些帮助

背景

支付(内购)的测试一直是一个比较棘手的问题,数据加密、第三方平台都是其中的难点。即便使用了沙盒等测试方式,各种中间环节的数据依然是不可控。测试人员大多只能做一些最基本的流程测试,比如正常走通流程、流程未完成等,有一些安全意识的测试人员还会尝试修改一些请求参数。

原理

要想进行全面深入的测试,首先要了解支付系统的实现原理。典型的实现如下:

无服务端

比如一个单机游戏,由 APP 直接向支付平台(以 APPLE 为例)发起支付请求,用户完成 APPLE 的支付流程后,APP 会收到 APPLE 返回的支付结果,通常包含一个返回码和一个票据,返回码用来标识支付是否成功。APP 根据返回码来决定下一步流程,比如发放物品给用户。

那么这里我们可以看到,只要在 APP 前拦截到支付响应并更改状态码为成功,就可以不花钱获得商品了。所以呢,这种实现方式是没有安全可言的,只要有些网络基础就可以对其破解。

不过大家应该不会遇到上面的这种实现(只有没有任何经验的开发者才会写出这种实现吧),因为通常支付平台都会提供一种本地验证数据有效性的方式。上面不是说到响应结果中包含一种票据么?这个票据是经过重重加密的,其中包含了很多信息,比如支付结果、购买的商品信息等等,只有经过正确的解密才可以看到。解密算法是平台提供给开发者的,于是一个合理的流程是,APP 拿到响应结果,解密票据,判断其中的信息是否正确,然后再决定是否发放物品。

这样,我们就无法像之前那样轻易的免费获取物品了。然而这样子还不能叫做安全,因为只要你了解了加密解密的算法,同样可以构造出合法的票据,只不过技术门槛变高了。

更进一步的说,任何客户端数据都可以进行破解。要想安全,一定要有服务端,接下来才是我们的重点。

有服务端

标准的实现方式是这样的

客户端的支付步骤和之前是一样的,但是 APP 得到支付结果后需要回调服务端,把支付结果告诉服务端。服务端再用票据去 APPLE 进行验证,根据验证结果来执行相应的流程。

这样,所有的数据处理都是放在服务端,客户端层面的任何数据篡改都会导致服务端的验证失败。

好好理解这个流程,然后再来想一想这样的一个系统有哪些测试点或者安全隐患,作为测试我们有哪些能做的?

注:

  1. 实际客户端向平台发送支付请求之前,一般需要先向服务端下订单,服务端返回商品信息并开启一个新的购买流程,这里为了简洁省略掉了。
  2. 回调逻辑可能与大家预想的不一样,我之前也以为回调应该是由支付平台发起。但 APPLE, GOOGLE 均为图中逻辑,PAYPAL 则为平台回调,所以要去看各平台的开发者文档。

传统测试

客户端层面的测试,一定是只能验证基本流程的,完成一次支付流程看看是否正确获得物品、中途中断、或者再继续完成支付等几个场景。

即使是通过一些接口测试的手段,因为核心的数据交互在服务端和支付平台之间(上图 4 和 5),也是无能为力的。只能发现更改了回调数据以后,服务端返回支付失败。

那么这样是否测试充足了呢?

测试场景

先来想象一些典型的测试场景,再考虑通过何种方式测试。这也是我经常对新人说的,最重要的是知道自己想做什么,然后再想怎么做。

下面这些场景都是传统测试无法实现的:

支付验证结果有多少种状态?每种是否触发不同的服务端逻辑?
异常情况如何处理?比如验证超时、无响应等
更复杂的商品如订阅(自行了解),如何操纵过期时间?
如何实现自动化?客户端层面去做也不是不可能,但是实在牵连太多

新的测试(mock)

考虑一下上面的问题就会发现,核心的核心就是我们需要控制支付平台到服务端的数据交互,这样也就间接控制了服务端的各种逻辑。

自动化测试同理,我们想要达到的效果是,不通过真实的购买就可以走完服务端处理流程。比如自己构造一个收据,服务端就可以验证成功。

要做到这种控制,只能通过 mock 来实现,将系统结构变为如下。

这时,已经没有外部支付平台的地位了,所有的数据流都在我们的控制之内。如何实现?很简单,只要把服务端代码的外部验证地址放到配置中,测试时修改配置就可以了。

mock server 主要实现两块逻辑,一是根据不同的地址返回不同平台的数据格式;二是实现控制逻辑,可以设定某个单据成功或是失败,或者是模拟各种异常状态。

那么,一个典型的测试用例就可以是这样的:

成功支付

  1. 客户端(测试代码)向服务端下一个订单,获取到商品信息
  2. 调用 mock server 的控制接口,声明某个票据或订单需要返回成功
  3. 直接构造支付成功的票据发往服务端
  4. 验证服务端返回的结果是否成功,并检查物品发放情况

再来个复杂一些的:
订阅过期

  1. 客户端完成一个商品订阅(比如有效期一个月,并验证成功)
  2. 调用 mock server 控制接口,设置某个订单的订阅状态为已过期
  3. 客户端使用此订阅商品的功能(一定是与服务端交互的)
  4. 验证服务端是否返回失败的状态

典型用例

到此,测试可以通过代码来实现,自动化就要发挥威力了。下面列一些典型的测试用例,都是发现过真实问题的哦,可以想一想如何实现用例。

  • 使用支付成功的收据多次回调(不要小瞧这个用例,很多人栽在这里)
  • 使用支付成功的收据并发回调
  • 使用其他成功订单的收据回调
  • 使用未回调的小金额订单收据回调大金额订单
  • 验证服务无响应、数据异常等

关于安全

所有的一切,我们都是基于两个假设:
支付平台是安全的。即查询某个订单返回支付成功,那这个订单就一定是已经支付的。
服务端本身是安全的。即用户无法拦截篡改服务端的数据,否则服务端也成了 “客户端”。

所以这里也可以稍微引申一些安全测试的层次,通常可按如下分:

  • 业务安全
  • 应用安全
  • 主机安全
  • 网络安全

我们上面所涉及的种种测试只可能属于业务安全。而像黑客登录了服务器(假设 2),篡改了验证结果,这种属于主机安全,是完全不同的领域。

业务安全上,也有太多的问题不是通过代码逻辑就可以简单解决的。最知名的就是刷单,也就是黑产,正常购买商品后再通过平台的渠道退款,商品是不会自动退回的。如果你们的业务很火,那么会有大量的人做这件事,需要花心思去避免这种损失。(我公司的一款产品每天被退款的商品超过 1W 刀)

一些建议

读支付平台的开发文档!!!
支付平台的开发文档,一般都会提供最佳实现方式。平台比个人更在意安全性。

看服务端源码
看得懂逻辑,才更可能了解逻辑的漏洞
比如服务端代码中有验证失败时重试的逻辑,如果不看代码是如何也想不到这里的测试点的。

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
共收到 16 条回复 时间 点赞

写的不错,可以具体事例再详细点就好😃

思寒_seveniruby 将本帖设为了精华贴 07月14日 20:01

加精理由: 理解的很透彻 文笔不错 加油哦

mock server 这个有公司到用么?第一次听说这个😂

chen 回复

mock 在服务端测试中还是蛮常用到的,可以模拟接口的返回值

我在做的项目中也有涉及支付环节,支付宝的支付流程应该是和 APPLE, GOOGLE 一样的逻辑。
但我们在异常测试时只覆盖了 “验证支付结果有效性” 时服务不可用的情况,没有考虑到 “支付成功的收据多次回调” 这些情况。
我当时测试时,是用支付宝真实支付的,开发将测试环境的商品价格都改成很低。当时的思路是直接 mock 支付宝回调的数据,但因为数据加解密流程太复杂,放弃了。没有想到文中对第三方支付进行整体 mock 的方法。
感谢分享,下次可以借鉴文中的做法😁

小敏 回复

对第三方支付进行整体 mock

这样也绕不过加密解密呀?

黑水 回复

文中的思路应该是把真实数据拷下来,用作 mock 数据吧?不需要自己进行加解密吧?

能否具体讲解一下 mock server 怎么做的,因为我现在做的项目涉及第三方支付,好在他们开放测试环境给我们测试,不然的话真是个很麻烦的问题。

黑水 回复

可以自己根据 md5 编码产生一个解码,绕过签名验证,就是很麻烦,需要了解 md5 编码的算法

感觉有具体的例子会好一些,可以讲一下具体的 mock 实现。

多谢分享 愿闻其详~😀

学习下~~~~

Ningxw 支付笔记 (1) 之 PayPal 支付原理 中提及了此贴 09月08日 10:56

请问您这个思路最终使用到项目上了吗?效果怎么样?

真实数据怎么拷下来的

simple 专栏文章:[精华帖] 社区历年精华帖分类归总 中提及了此贴 12月13日 14:44
simple [精彩盘点] TesterHome 社区 2018 年 度精华帖 中提及了此贴 01月07日 12:08
小敏 回复

为什么一定要加密,mock 就是要摒弃麻烦浪费时间的部分,剩余部分可以联调时测试

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册