本周二, 去外面吃了个饭, 扫码点餐,微信支付, 成功付款26元, 但页面提示失败, 且提示让我稍等, 不要尝试继续支付。 等了一会儿,没有结果。 店里人很多, 没来得问是什么情况, 就再次支付了, 第二次成功。当我查看微信支付记录的时候, 发现扣款两次了。 1分钟后, 另外一个吃饭的人, 也反馈了这个问题, 我们找老板反馈, 老板同意退钱, 甚好。 其实, 这种重复扣款的问题, 是有解决方案的。本文来说说与此相关的一些问题。

 

       先说说重放, 顾名思义, 就是对客户端发的网络请求包进行replay操作, 如果不采取措施, 肯定会导致服务端的重复动作, 这就是重放攻击。重放攻击的特点是, 两个请求完全一致, 所以, 从直观上来看, 要抵抗重放攻击, 服务端进行除重就可以了。比如,每次请求,客户端随机生成一个random值,放在参数中。如果是重放攻击, 那么这个random值就重复了, 服务端判定为重复包。通常的做法还会在参数中增加当前时间戳,并hmac签名生成token(sign)防篡改, 服务端会校验token(sign)和时间差。

       其实, 计算机中的很多原理,都是一个套路, 来源于生活逻辑, 很多都是合情合理的推理。

 

       再说说幂等性, 查了不少资料, 发现这个定义其实很模糊, 简单来说, 就是, 客户端(或者用户)发起一次或者多次相同操作,不会产生副作用。有点抽象, 没关系, 还是以类似的上述情形为例:客户端给服务端发送扣款请求, 如果服务端扣款成功, 但是在给客户端返回成功的结果时失败了, 此时, 客户端看到了失败, 以为是服务端没有扣款, 于是客户端重试, 悲剧就发生了------重复扣款。

        这种接口,是没有幂等性的, 无法防止重试,客户端和服务端都忧心忡忡。 一个简单的解决办法就是, 客户端携带随机数, 自动重试时,随机数相同,服务端要判断这个随机数对应的请求在之前是否被处理成功, 避免重复扣款。另一个类似的思路是, 客户端每次都去服务端拉一个随机数(可以理解为服务端分配的订单号), 然后服务端就可以判断了。 随机数在客户端还是在服务端,道理一个样。 此时, 接口就有了幂等性。 

 

       回到我碰到的那个问题, 很简单, 客户端把订单号带上就可以了, 同一订单,服务端可以防止重复扣款。

 

       26元算是讨回来了。

       不多说。

 

 


本文转载:CSDN博客