银行卡支付是现代生活中必不可少的一部分,但其背后的产品设计还是非常精妙的,本文笔者就银行卡支付的原理进行分析整理,分享给大家。
上次写了一篇《只需扫一扫,立刻扣钱,你不想知道支付码背后的原理吗?》今天小黑哥再来跟大家聊聊支付这件事。
虽然现在我们主流的支付方式是支付宝/微信支付,但是当我们的余额不足或者选择从银行卡扣款的时候,我们就会使用银行卡支付。
那么今天我们就来聊一聊银行卡支付的相关原理,科普一下银行卡支付的整个流程。
银行卡支付分为线上支付和线下支付,线下支付分类比较简单,就是我们平时在商场购物的时候,通过在POS机上刷卡支付。
网上支付的种类很多,按照银行卡类型可以分为信用卡支付、借记卡支付;按照支付行为可以分为快捷支付、网银支付、支付宝支付。
今天我们主要讲快捷支付和网银支付,这两个是目前最流行的两种支付方式,其他方式以后再讲。
1. 网上银行支付
首先我们来说说网银支付,网银支付在10年前应该是最主流的网上支付方式。
就拿电商购物来说,我们在网站上下单之后,如果选择的是银行卡支付,一般会跳转到收银页面,然后在收银页面选择相关的银行,点击银行支付,最后跳转到对应的银行页面。
这个收银页面可能是商户的页面,也可能是支付机构的页面,这个和网银支付对接模式有关。
跳转到银行页面之后,我们首先需要下载银行安全控件,这样才能录入银行卡的相关信息。其次,我们还需要使用银行提供的安全设备,比如U盾、设备、码等。
在银行网站支付成功后,可以点击返回跳转回电商网站,整个流程如下图所示:
网上银行支付流程
后端支付流程如下:
可以看出,网银支付整个流程非常长,任何一个步骤都有可能失败,所以支付成功率并不是很高。另外,有些银行网银页面只能在IE中打开,而且可能是IE版本非常老。另外,为了保证网银支付的安全,还需要使用U盾,安装安全插件。
说实话这个过程还是很复杂的,还记得之前用某银行网银充值买黄钻的时候,折腾了一下午都没成功,各种证书安装失败等等,第一次网银充值,就以失败告终。
感谢有人帮我省了10元零花钱~
2. 快捷支付
快捷支付是指用户向电商商家提供卡信息,商家在后台将卡信息传给支付机构,然后进行协议绑定,一旦绑定成功,用户下次支付时无需提供卡号等信息。
以电商购物支付为例,首次支付需要经过绑卡流程。
扣款成功后,到银行APP查看该卡与支付机构的绑定记录。
在电商网站下单付款时,您无需输入您的卡信息,因为电商网站已经保存了记录。支付流程如下:
上图是每次支付过程中都需要输入验证码,这个步骤其实可以实现一定金额的免密码支付。
快捷支付接口一般可以分为两类:
签订合同/付款 扣款 1. 签订合同/付款
签约/付款需要两个步骤:
合同申请/合同验证付款
签名过程需要传入银行卡信息,银行卡号,账户名,身份证号,手机号,信用卡信息,可能还需要传入CVV2,有效期等,这个过程主要是为了认证,验证银行卡信息的正确性。
支付机构/银行信息验证成功后会发送短信,用户回复短信即表示同意开通快捷支付并建立绑定关系,绑定成功后支付机构会返回商户的协议号。
在支付过程中,商户可以使用协议号扣取款项。
整个后台流程如下:
2. 扣留付款
代扣付款的流程相对于签字/付款来说比较简单,每次提交银行卡信息就可以直接扣款,代扣付款原则上是不需要密码就可以完成的,也就是不需要输入验证码就可以完成扣款。
流程比较简单,具体请参考快捷支付流程。
![]()
相对于签约/付款流程,直接扣款看似更快捷,但这种方式的安全风险比签约付款更大,容易出现欺诈。原本直接扣款接口应该是适用于水电煤气等扣款场景,但在开发过程中也曾被用在金融支付等场景。
现在这种接口正在慢慢下线,被新的业务委托接口(类似签约/支付)取代。
快捷支付虽然拥有良好的支付体验,但整个过程不需要跳转银行页面,支付过程不会中断,支付成功率较高。
但易用性和安全性永远是矛盾的,由于用户在这个过程中需要向商户提供银行卡相关信息,如果这些数据被窃取,资金就有可能被盗用。另外,对于快捷支付来说,手机验证码可能是最后一道防线,如果手机丢失,银行卡资金也可能被盗用。
3. 银行付款相关问题
总体来说,接入银行卡支付通道的整个流程难度不是很大,无非就是按照接口文档,拼接参数,然后做一些相应的调试即可。不过,在这个过程中,还是有一些点需要特别注意的。
1. 添加/验证签名
银行卡支付一般通过互联网传输,为了防止消息被篡改,通常采用RSA2、国密等加密算法对消息进行加密,获取签名串,然后一起发送给支付机构。
支付机构会进行相应的签名验证,如果签名验证失败,则拒绝支付请求,这样可以有效保证支付请求是由合法商户发起的,因此对于商户来说,保管好相应的公钥和私钥,不要随意泄露是十分重要的。
另外,支付机构还会对支付请求/网银结果异步通知的响应信息进行签名,商户必须进行签名验证,签名验证通过后才能进行下一步操作。
ps:由于不签署请求就无法进行交易,所以这一步是一定会做的。
但是,如果您不验证返回信息的签名并且仍然可以处理该消息,那么这可能会被忽略。
刚开始对接相关支付渠道的时候嫌麻烦,没有验证签名,现在想想,真的是太粗心了……
2. 最终状态确定
对于快捷支付等同步接口,我们需要根据支付接口请求响应消息返回的响应码来判断请求是否成功,有些接口可能还会返回响应码和支付状态,所以需要将两者结合起来进行判断。
这个过程并不是说除了成功之外的其他响应码都算是失败,需要根据相关的接口文档来进行分类,当然有些错误码比如余额不足,卡要素不正确等也可以明确的归类为失败。
但有些返回码比如处理过程中的返回码或者系统异常的返回码,并不能明确是成功还是失败,我们不能将其设置为失败,需要结合支付查询或者异步通知的结果再进行处理。
对于网银支付等同步接口,只能等待渠道端的异步通知,一般来说,渠道端只会通知支付成功的订单。
这是专门基于渠道接口文档的。
一般来说,如果渠道异步通知接口没有返回渠道异步通知的成功响应,那么将会重复通知,直到达到一定次数或者得到成功响应。
所以在收到异步通知后,必须内部逻辑处理成功后,才能返回成功响应码给渠道端,这样即使内部逻辑处理失败,也可以通过异步通知再次处理内部逻辑。
另外还要注意内部处理逻辑的幂等性。
3. 请求参数相关
(1)付款金额
在请求过程中一定要注意接口单据里的付款金额单位,是分还是元,如果不注意单位的话,很有可能造成少收或者多收的情况。
对于成功响应信息,我们还需要检查提交金额和扣款金额(如果有)的一致性,如果不一致,**不更新订单为成功**,并及时进行人工干预检查订单。
最后,支付通道上线后,需要进行一些真实扣款,比如0.1小额扣款,以及通道最大金额的测试。扣款成功后,还需要及时检查银行卡实际扣款金额与提交金额是否一致,原因如下。
(2)请求序列号(订单号)
除了支付金额,我们还需要注意请求序列号/订单号的唯一性,需要使用唯一ID作为请求序列号,切勿使用时间戳等方式。
对于重复的序列号,如果支付失败,可以重复支付,如果支付成功,则不允许再支付,但有些机构的接口这部分验证做的并不好。
举个我遇到的坑,这个教训让我损失了几万块钱,我之前对接过一个银行的系统,测试的时候为了方便,直接用时间戳当序列号。
这个问题在上线时没有及时发现,某天同一秒生成了两张同号的订单,并发送到银行,对方随后返回两张订单均成功到账,但第二天对账时发现只有一张订单的款项到账,幸好最后人工追回了款项,不然当时卖掉也赔不起了。。。
虽然这个例子中银行端肯定会有问题,因为没有做防重复处理,但是只要有唯一的流水号逻辑,就可以避免这个问题。
一个真实的悲剧例子
上面讲了这么多问题,其实是想提醒对接渠道的技术人员注意,不要以为支付机构或者银行的系统稳定,就不会出问题。
程序毕竟是人编写的,一次升级或者改变都可能带来巨大的生命损失。
所以不要太相信对方系统的稳定性,我们能做的就是保证自身系统的稳定性,增加各种参数检查,尽量降低风险的发生。
以下是一些悲惨的例子:
我们之前对接过银行,测试过小额度,完全没问题。但是测试限额的时候,比如限额是1000元,我们测试了1000.01,支付失败也是情理之中。
但是扣款成功了,银行的扣款记录显示只扣了0.01。看到这个,是不是有很多疑问???这TM限额溢出了。。。
唉呀,对于这种问题,只能紧急关闭通道,等待银行修复。
最后我给大家举几个网上关于支付漏洞的例子。