本篇文章主要介绍服务端sdk的集成与使用、微信支付的流程逻辑、微信支付的安全原理,并介绍开发微信支付前的一些准备工作。
在正式接入微信支付小程序支付服务前,需要进行以下准备步骤:
上述三点的具体步骤已经在上一节说明。
为了帮助开发者调用开放接口,微信官方提供了JAVA、PHP、GO三种语言版本的开发库,封装了签名生成、签名验证、敏感信息加/解密、媒体文件上传 等基础功能。
使用微信支付 SDK,将体验到以下优势:
所以通过服务端的sdk,我们可以快速调用微信提供的api接口,并省去了网络请求和加密、解密、加签、验签的步骤。官方推荐的服务端sdk为:wechatpay-java。网上大多数案例都是使用旧版的sdk (wechatpay-apache-httpclient),这个官方大部分示例都是基于这个写的。要想使用wechatpay-java,我们需要读懂其中的源码,并使用其提供的api。后面的文章将会详细提供基于wechatpay-java的示例代码(支付、下单、查单、取消订单、退款、查退款单等)。
maven集成wechatpay-java
<dependency>
<groupId>com.github.wechatpay-apiv3</groupId>
<artifactId>wechatpay-java</artifactId>
<version>0.2.12</version>
</dependency>
在开始写代码之前,我们先来理清楚,我们都需要完成哪些接口的开发,以及每个接口开发时都需要注意什么。
针对保证金项目,当用户在小程序选择金额支付时,首先会调用小程序下单接口,下单成功后返回小程序客户端,在小程序客户端发起微信支付(调起支付是客户端的api),当调起支付成功时,同步从微信返回结果,如果成功则微信支付成功,否则失败。此时,并不能确定是否真的支付成功,系统并没有更新订单的状态,所以在系统中,我们需要提供一个url地址供微信回调或通知我们实际的支付状态,并根据实际的订单状态来处理我们的业务数据。然而,当我们的系统因网络异常出现微信无法调用回调接口时,微信为我们提供了一个主动查询订单的接口,用来判断订单的实际状态。当用户下单成功后,不想支付时,则可以关闭订单。因此支付过程中我们要完成以下几个接口:
具体的业务流程图如下:
下面是开发过程中重点关注的步骤。重点步骤说明如下:
步骤4: 用户下单发起支付,商户可通过JSAPI下单创建支付订单。
步骤9: 商户小程序内使用小程序调起支付API(wx.requestPayment)发起微信支付,详见小程序API文档 。
步骤16: 用户支付成功后,商户可接收到微信支付支付结果通知支付通知API。
步骤21: 商户在没有接收到微信支付结果通知的情况下需要主动调用查询订单API查询支付结果。
在前面的信息安全一节中已经详细介绍了如何保证信息安全的措施,那么在微信支付或退款以及微信支付功能的所有接口中是如何保证信息的传输安全呢?其实都是一样的,下面来看看在微信支付时,都需要哪些密钥和证书。
主体
微信支付模块的主体为商户
和微信平台
。信息在商户和微信平台之间进行传输时需要将信息加密和签名。
安全机制
简单来说就是商户将消息进行加密、签名,微信支付平台收到后对消息进行验证签名和解密
。微信支付使用商户的消息签名验证商户的身份。如果一个请求不包含签名或者签名验证失败,微信支付将返回身份验证错误。它背后的技术是:数字签名技术。数字签名(亦称公钥数字签名)是一种独特的数字串,只能由信息发送者生成,且无法被他人伪造。它有效地证明了发送者发送信息的真实性。数字签名类似于纸上的普通物理签名,但采用了公钥加密技术来实现,用于验证数字信息的真实性。数字签名系统通常包含两种互补操作:一种用于生成签名,另一种用于验证签名。
应用场景
商户请求微信支付、微信支付应答商户、微信支付回调商户、查单,退款、退款通知。以上所有的接口都需要安全机制。
证书种类
商户API证书: API证书,是指由商户申请的,用来证实商户身份的证书。API证书由证书授权机构Certificate Authority(简称CA)颁发。证书中包含商户的商户号、公司名称、公钥等信息。此API证书就是指商户的公钥文件,是商户用来进行对消息加密使用
或微信平台用来对消息进行验证签名
的。具体的申请方式 商户API证书申请步骤。商户号注册后,需要商户自行申请。每个证书都有一个由CA颁发的唯一编号,即证书序列号。使用时可以在商户平台查看序列号(代码中我们会使用此序列号),
商户API私钥: 指的是商户的私钥,和商户的公钥文件成对出现,是微信支付侧用来对消息进行解密
或商户对消息进行签名的
。商户申请商户 API 证书时,证书工具会生成商户私钥,并保存在本地证书文件夹的文件 apiclient_key.pem 中。私钥也可通过工具从商户的 p12 证书中导出。
微信平台证书:微信支付平台证书是由 证书颁发机构 颁发,由微信支付平台 申请和管理的数字证书,它包含了微信支付平台的身份标识和公钥信息。每位商户都会分配到一个或多个微信支付平台证书。在处理接口响应或回调通知时,商户需要根据证书序列号选择对应的平台证书,并使用其中的公钥进行签名验证。其包括两部分内容:微信支付平台私钥
和 微信支付平台公钥
。微信支付平台证书的有效期为5年。
公钥和私钥的用途有两个,(1)当商户主动请求到微信支付平台时,使用平台的公钥对信息进行加密,微信支付平台收到信息后则使用平台的私钥进行解密。(2)当微信支付平台同步应答商户的请求时(如请求支付回调方法)微信平台会使用平台的私钥进行加签,商户收到信息后会使用平台的公钥进行验签。
APIv3密钥:API v3密钥主要用于平台证书解密、回调信息解密。微信平台证书不需要我们申请,但是使用微信平台证书时需要我们在代码中去下载,下载的api在sdk中已经提供了,所以我们可以直接调用。下载的证书需要使用对称密钥进行解密,APIv3密钥就是此对称密钥。在微信支付回调中,微信平台需要主动调用商户提供的接口,这时使用加密的密钥就是对称密钥,也就是APIv3密钥。
数字签名定义了两种运算: 签名和验签。使用数字签名时,需要通信的双方都要事先生成公钥、私钥,并且完成交换。但是由于公钥本身并不含有拥有者的身份信息,使用时无法确认它是真实有效的。
所以需要证书认证机构(简称 CA)在核实公钥拥有者的信息后,将公钥拥有者的身份信息(如商户号、公司名称等),公钥、签发者信息、有效期以及扩展信息等进行签名,制作成“证书”。
简单理解就是:证书包含公钥,同时还包含公钥所有者、签发者、有效期等关键信息,使用者可以验证其真实性。
单从加签、验签的过程来看,确实可以不需要证书,只要交换好公私钥就行了。不过前文已经提到,公钥的劣势在于无法核实其真实性,那么就容易遭到中间人攻击(man-in-the-middle attack)。
示意图如下:
(1)Alice将公钥:PK_A 传送给Bob。
(2)Mallory截取了这个密钥并将自己的公开密钥:PK_M 传送给Bob,并声称这是Alice的公钥。
(3)Bob用“Alice”的公开密钥(实际上是Mallory的公开密钥)加密的消息传送给Alice时。
(4)Mallory截取它。并用他的私人密钥解密消息。
(5)Mallory篡改了明文,再用Alice的公开密钥:PK_A 重新加密,并将加密后的消息传送给Alice。
(6)Alice使用自己的私钥对消息进行解密,得到明文。(实际已经被Mallory篡改)
这种攻击是完全可行的,因为Alice和Bob无法验证他们的互相交谈。如果Mallory没有导致任何值得注意的网络延迟,两人就没有办法知道有人在他们中间阅读传输的信息。有了证书之后,Alice和Bob能够验证对方的公钥所有者、有效期,那么Mallory便无法用自己的公钥进行伪装,便无法进行中间人攻击。商户和微信支付便是例子里的Alice和Bob,Mallory代指所有可能的恶意攻击者。
微信支付平台证书是由 微信支付 负责申请和管理的,该证书包含了微信支付平台的身份标识和公钥信息。每位商户都会分配到一个或多个微信支付平台证书。在处理接口响应或回调通知时,商户需要根据证书序列号选择对应的平台证书,并使用其中的公钥进行签名验证。微信支付平台证书公钥所对应的私钥由微信支付所有,在微信支付保管。
微信支付平台证书和微信支付平台私钥的用途:
为了保证安全性,微信支付在 回调商户 和 平台证书下载接口 中,对关键信息进行了AES-256-GCM加密。API v3密钥是加密时使用的对称密钥。注意回调商户和平台证书下载接口的加密方式略有不同:
请求过程:
(1) 商户构造原始请求。
(2) 商户使用平台证书公钥对请求中的敏感字段进行加密,得到新的请求包体,注意是对敏感字段加密,而非整个原始请求
(3) 商户使用商户API私钥对请求包体计算签名,详情见:生成签名。
(4) 商户将请求包体和签名上送到微信支付。
(5) 微信支付使用商户API证书公钥对请求包体进行验签。
(6) 微信支付使用平台私钥对请求中的敏感字段进行解密,得到原始请求,随后开始处理业务。
如下图所示:
应答流程
(1) 微信支付构造原始应答。
(2) 微信支付使用商户API证书公钥对应答中的敏感字段进行加密,得到新的应答包体。
(3) 微信支付使用平台私钥对应答包体计算签名。
(4) 微信支付将应答包体和签名返回给商户。
(5) 商户收到应答后,应使用微信支付平台证书公钥进行验签,以校验应答者的身份真实性。
(6) 如果应答中包含敏感字段,应使用商户API证书私钥进行解密。
微信支付回调商户时,与前述略有不同,主要体现在加密和签名的源串不同。
(1) 微信支付构造原始请求
(2) 微信支付使用APIv3密钥对原始请求进行加密,得到新的请求包体(注意:APIv3密钥是一个对称密钥,由商户在商户平台设置)
(3) 微信支付使用平台证书私钥对原始请求计算签名
(4) 微信支付将请求包体和签名上送到商户
(5) 商户使用APIv3密钥对请求包体进行解密,得到原始请求
(6) 商户使用平台证书公钥对原始请求进行验签,验签通过后开始处理业务。
本节主要介绍了服务端sdk的集成、我们在开发中都需要开发哪些接口、微信支付的api证书的种类及每种证书在微信支付安全中的作用。下一节我们将介绍如何获取这些证书,并结合微信平台证书下载接口和微信支付下单接口来讲解服务端sdk的使用、APIv3密钥在微信平台证书下载中的使用。此外还要结合SDK源码来解读商户的API证书和私钥、微信平台证书在统一下单api的使用及源码解读。统一下单接口只是解读sdk使用的案例接口,后面的接口将以业务为主。