buguge - Keep it simple,stupid

知识就是力量,但更重要的,是运用知识的能力why buguge?

导航

支付结果回调通知的安全控制(嘘,一般人我不告诉他~~)

写在前面

支付结果回调通知:支付完成后,上游第三方支付渠道会把支付成功的结果以回调通知的形式发送给商户系统,商户系统需要接收处理,并按文档规范返回应答。

 

上游发送通知,安全方面会做数据签名(根据特定签名规则,通过商户号和签名私钥来生成),请求报文里会包含支付信息(如支付单号、支付金额)。

 

微信支付官方文档上有如下几个特别提醒:

1、商户系统对于支付结果通知的内容一定要做签名验证,并校验返回的支付金额是否与商户侧的支付金额一致,防止数据泄漏导致出现“假通知”,造成资金损失。

2、当收到通知进行处理时,首先检查对应业务数据的状态,判断该通知是否已经处理过,如果没有处理过再进行处理,如果处理过直接返回结果成功。在对业务数据进行状态检查和处理之前,要采用数据锁进行并发控制,以避免函数重入造成的数据混乱。

 

不过,我们的聚合支付系统还真出现“假通知”了。就是说,我们系统收到了支付结果通知,而经与上游三方系统确认,上游系统并未主动通知我们。经查,发现是湖南长沙的代理IP发过来的。我们系统程序按照正常的逻辑接收并处理了支付单,最终导致了资金损失。

由此,我们程序又进一步加强了安全方面的控制。见下文。

 

通知地址(notify_url)差异化处理,

  1. 每笔交易发给渠道方的通知地址都不一样
  2. notify_url中不能包含敏感数据,如自增id,而且通过加密混淆来保证URL不容易被模仿

 

接收到通知请求后,

api层:

  1. 验证IP白名单
  2. 验证请求url的合法性

渠道层:

  1. 严格对请求参数做非空校验
  2. 比如, ● 上游三方渠道在通知时传递支付金额,那么,当某次通知的参数里没有支付金额时,就认定是非法通知; ● 某渠道文档说明了在通知时传递支付账号,那么,当某次通知的参数里没有支付账号时,就认定是非法通知
  3. 数据的合法性校验,如金额必须为数值

Service层:

  1. 支付单是否存在
  2. 验证当前支付状态,如果是终态,则终止处理
  3. 如果渠道有如下请求参数:
    •   验证支付金额是否一致
    •   支付账号是否匹配
    •   验证请求url的合法性(如果某渠道定义了特定的url规则)
    •   对于扫码支付:验证通知时间 如果在支付时间的24小时之后,则认定为非法通知(如果是其他支付方式,需另做相关控制)
    •   验证支付完成时间 如果早于支付时间,则认定为非法通知

 

————————————————————–我是萌萌哒分界线————————————————————

写在后面

【PDCA】

程序上线后,经过监控,在时间验证方面数次发现,渠道方的通知报文里的支付完成时间早于我方的支付发起时间!经进一步分析得知,两组时间的差异均在5秒之内,不难推断出,这是双方服务器时间不一致导致的,事实上也往往无法保证两台服务器的时间完全一致。 所以,需要对时间验证做完善,设置一个阈值,比如2分钟,支付完成时间不能早于支付时间减去这个阈值。这样,就可以兼容这种实际情况下的不一致。

posted on 2018-02-27 18:52  buguge  阅读(565)  评论(0编辑  收藏  举报