频道栏目
首页 > 资讯 > 其他综合 > 正文

互联网支付-退款中多证书情况下串证书Id

16-12-27        来源:[db:作者]  
收藏   我要投稿

我在做A公司的互联网支付项目,他们的支付方式有代收和B2C两种,也就意味着他们有两个证书证书ID - CertId, 有两个证书Id无所谓,可是当时 出现的情况是 代收退款测试好了,再接着做一笔B2C的退款就会报错--验签失败; 或者 B2C退款刚调试好,再接着做一笔 代收退款就会报错--验签失败。

当时试着改了很多东西,可是仍会出现这种问题后来比对JBOSS日志nohup里面代收 和 B2C 发往银联的报文 开始只去跟银联的接口文档对比传送的字段发现并不缺少字段,还多了一个certId的字段,有个certId的字段 有时会一样 ,有时会不一样,怀疑是证书加载时串了证书Id 代收和B2C 各有一个证书, 由于证书ID--certId 是最后加载到那些传送到银联的报文里面的.

(查看含有向银联发送和返回报文时,可以去看trc日志,也可以看jboss的日志nohup.out .nohup.out 中的日志中有发送给银联前的验签报文留意 发送给银联前的验签报文,里面不只有发送给银联的字段还有证书ID--certId)

比对发往银联的报文

B2C
17:47:51,966 INFO  [ACP_SDK_LOG] 报文签名之前的字符串(不含signature域)=[accessType=1&acqInsCode=49316100&backUrl=https://callback.hdwtpay.com&bizType=000201&certId=70196016930&channelType=07&encoding=UTF-8&merAbbr=JFT&merCatCode=5311&merId=993450153110009&merName=JFT&orderId=0009450100005385&origQryId=201612151746417026148&signMethod=01&txnAmt=1&txnSubType=00&txnTime=20161215174751&txnType=04&version=5.0.0]
代收
23:16:07,022 INFO  [ACP_SDK_LOG] 报文签名之前的字符串(不含signature域)=[accessType=0&acqInsCode=49316100&backUrl=https://callback.hdwtpay.com&bizType=000301&certId=70196016930&channelType=07¤cyCode=156&encoding=UTF-8&merAbbr=JFT&merCatCode=5311&merId=993450153110001&merName=JFT&orderId=q4501000100005410&origQryId=201612152306408691878&signMethod=01&txnAmt=2&txnSubType=00&txnTime=20161215231606&txnType=04&version=5.0.0]

这两个发往银联的报文中的字段可以明确地看出certId是相同的,按说两种业务,他们的证书ID是不同的(其他的字段不用管,其他的字段值,我们明确知道两种业务该用什么值来标识)
查看jar代码 发现这个certId是以静态类变量 加载在 类代码块里面的,这样当前商户的sessionId保存期间每次加载这个类的时候,certId 是不会变的,所以才会出现了 测试B2C退款正常之后,紧接着测试代收的退款就会报错;测试代收退款正常之后,B2C退款失败这种问题。

 

解决办法 是修改加载正式时不用静态代码块的方式(银联提供的JAR包加载证书的方式--单证书模式),改为每个向银联发送报文时重新到放B2C和代收的证书的路径下面去加载证书,证书密钥 (这个银联提供的jar里面有重写过的加载证书的方法,可以直接复用)同时下面还有个方法是加载密钥的方法,也要进行替换,改为每次加载证书时再重新加载密钥(这个银联提供的jar里面有重写过的加载证书的方法,可以直接复用)

总结:不要想当然认为银联提供的证书就没有问题,银联提供的代码调用默认是单证书;如果是两证书或者是多证书就要去修改代码改为每次加载证书时重新去相应目录下去加载证书,这些方法都在银联提供的jar里面,稍微改下就行.

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

(以下记录的具体类代码名称 是我们项目里面具体的类名,做个记录防止遗忘。非我们项目组的人可以忽略
CertUtil.class加载证书的Util类,隶属于upacp_sdk-1.0.0.jar
FQpayUpopRefund.class 银联快捷退款的类 隶属于 mrqpupop.jar
SDKUtil.class 隶属于 upacp_sdk-1.0.0.jar

UpopBase.class 隶属于 mrqpupop.jar)

一步步跟着调用去查看源代码

代收退款的类FQpayUpopRefund,在下图红线之前,通过比对日志发现都是正确的,有问题的是后面的代码,这样就要去查看 UpopBase 中的submitDate方法,如图2

图一 FQpayUpopRefund.class

 

图二 UpopBase 中的submitDate方法
UpopBase.class 中的submitDate 紧接着调用signData方法,见图三UpopBase.class的signData方法,该方法里面调用了SDKUtil类里面的sign签名方法
图三 UpopBase.class的signData方法
原来的SDKUtil方法 在获取证书时只是调用了CertUtil的无参构造函数,图四是最原始的SDKUtil.class方法,这两个方法的使用要去看源代码图五会发现他去取keyStore的值,接下来就是问题的关键所在,去找keyStore是如何生成的。
图四是最原始的SDKUtil.class方法
图五getSignCertId去取keyStore
 
KeyStore 是CertUtil.class中的静态类变量,全局性变量,具有一改全改的特性keyStore 是静态类变量, 没有问题。接着发现CertUtil.class中有静态代码块的出现。static init {} 静态代码块(见图七),图七的方法题在图六中,我们知道静态代码块只在项目启动的时候就执行的时候加载一次,每次再调用类时,那些静态代码块里面的方法都不会在加载,所以在问题就出在这里,这个静态代码块里面初始获取的证书路径,证书密码 和证书类型,之后每次调用该类时,这个静态代码块不会再被调用。
其实静态代码块也没有错,错就错在我们有两个证书,证书号不一样,证书号不一样也无所谓,其他有一个证书的支付公司不会产生最开始串证书Id的问题,错就错在每次加载获取证书ID的时候图五源代码里面只获取静态代码块里面的数据keyStore,不重新加载获取,这就出现了问题,产生了测试B2C退款正常之后,紧接着测试代收的退款就会报错;测试代收退款正常之后,B2C退款失败这种问题。
图六 keyStore变量
图七 静态代码块 init

 

 

解决办法:

 

方法一:我们采用了这种方法在SDKUtil 验签sign 方法中 再一次加载获取一次证书,每一次验签都重新加载,如图八,CertUtil类里面有相应的方法 ,CertUtil.getCertIdByCertPath(path, pwd, certTp)
CertUtil.getSignCertPrivateKey(path, pwd)
不用我们重新写方法。
方法二:也可以每次需要keyStore的时候,重新加载,当然功能和思想上跟方法一完全一样,就不再赘述了。
图八 通过证书路径,每次调用sign 方法都加载一次证书Id

 

 

 

--------------------------------------------------------------------------------------------------------------

源代码

FQpayUpopRefund.class
CertUtil.class
SDKUtil.class --原来的版本

SDKUtil-modify.class --修改后的版本,此次就修改该类

想提供源代码,CSDN怎么提交提交源代码到文章呢

相关TAG标签
上一篇:知识库--StandardContext+backgroundProcess(60)
下一篇:从零开始做远控 第十二篇 命令行控制
相关文章
图文推荐

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训 | 举报中心

版权所有: 红黑联盟--致力于做实用的IT技术学习网站