支付接口交易安全需要以商户校验码来保证。商户校验码的作用,是防止商户生成的订单内容在提交银行之前被恶意修改。
每个商户有一个“商户密钥”,可以自行在招行提供的商户管理系统中维护。商户校验码,就是使用这个商户密钥,对订单内容做运算后得到的。订单内容不同,其校验码也不同。只有商户和银行知道“商户密钥”,第三方无法产生正确的校验码。因此商户需要妥善保管商户密钥,防止非法泄露,建议定期修改商户密钥。
要使用商户校验码,需要先设置“商户密钥”。设置方法:登录招行的“网上商户结账处理” 系统进行设置(登录类型选择:系统管理员),招行主站www.cmbchina.com上有登录入口。预登录密码:75268。
使用商户校验码的方法:
在支付表单请求中,增加一个参数(黑体字部分)“MerchantCode”。MerchantCode字段的值由开发包中的api产生。
例子
<form action="https://netpay.cmbchina.com/netpayment/BaseHttp.dll?PrePayEUserP" method="post">
<input type="hidden" name="date" value="20080219">
<input type="hidden" name="cono" value="002696">
<input type="hidden" name="branchid" value="0571">
<input type="hidden" name="billno" value="0000000001">
<input type="hidden" name="amount" value="123.01">
<input type="hidden" name="MerchantUrl" value="http://merchantsite.com/proc">
<input type="hidden" name="MerchantPara" value="abc">
<input type="hidden" name="MerchantCode" value=" 由商户服务器生成的校验码">
</form>
生成校验码的接口说明:
Java版本
类:cmb.MerchantCode
方法:public static String genMerchantCode(String strKey, String strDate,
String strBranchID, String strCono,String strBillNo,
String strAmount,String strMerchantPara, String strMerchantUrl, String strPayerID,String strPayeeID, String strClientIP, String strGoodsType, String strReserved)
参数说明:
参数 |
长度 |
是否可为空 |
说明 |
示例值 |
strKey |
16 |
是 |
商户密钥 //测试环境为空, 生产环境见《一网通支付商户服务指南.doc》 |
|
strDate |
8 |
否 |
订单日期 |
|
strBranchID |
4 |
否 |
开户分行号 |
|
strCono |
6 |
否 |
商户号 |
|
strBillNo |
10 |
否 |
订单号 |
|
strAmount |
18 |
否 |
订单金额 |
|
strMerchantPara |
128 |
是 |
商户自定义参数 |
|
strMerchantUrl |
256 |
否 |
商户接受通知的URL |
|
strPayerID |
40
|
是 |
付款方用户标识。用来唯一标识商户的一个用户。长度限制为40字节以内。
并不要求商户提供用户的注册名称,但需要保证一个用户对应一个UserID。
商户可以通过某些转换,把用户名转换为一个UserID。比如商户可以把用户注册的“日期+时分秒毫秒”作为UserID。如果还有重复,可再加上用户的IP。
空白表示匿名用户。
|
|
strPayeeID |
40 |
是 |
收款方的用户标识。生成规则同上。 |
|
strClientIP |
60 |
是 |
商户取得的客户端IP,如果有多个IP用逗号”,”分隔。长度限制为60字节。 |
|
strGoodsType |
8 |
是 |
商品类型,长度限制为8字节。 |
|
strReserved |
1024 |
否 |
保留字段,长度限制为1024字节。
填写内容为<Protocol>……</Protocol>。各字段说明如下:
<Protocol>
以下字段必填:
<PNo>客户协议号</PNo>
<TS>交易时间</TS>
<MchNo>协议商户企业编号</MchNo>
以下字段“签约+支付”时必填:
<Seq>协议开通请求流水号</Seq>
<URL>协议开通结果通知命令请求地址</URL>
以下字段选填:
<Para>协议开通结果通知命令参数</Para>
<MUID>协议用户ID</MUID>
<Mobile>协议手机号</Mobile>
<LBS>地理位置</LBS>
<RskLvl>客户风险等级</RskLvl>
</Protocol>
|
<Protocol>
<PNo>客户协议号</PNo>……
</Protocol>
|
返回值:返回String类型,即生成的MerchantCode。把这个返回值放在订单支付表单的MerchantCode字段中,向银行提交支付请求。
关于strReserved 参数中一网通支付协议相关的字段(<Protocol>/<Protocol>节点中)的填写说明:
PNo: 客户协议号。必须为纯数字串,不超过30位。未签约(首次支付)客户,填写新协议号,用于协议开通;已签约(再次支付)客户,填写该客户已有的协议号。商户必须对协议号进行管理,确保客户与协议号一一对应。非空。
TS:交易日期+时间,格式为YYYYMMDDHHMMSS。非空。
MchNo: 协议商户企业网银编号。由银行在商户开户时确定。非空。
Seq:协议开通请求流水号。字符串,不超过20位。开通协议时非空。
MUID:协议用户ID。字符串,不超过20位。开通协议时使用,可空。
Mobile:协议手机号。11位数字。开通协议时使用,可空。
URL:协议开通结果通知命令中参数之前的部分。参数规则同支付结果通知命令。字符串,长度不超过100位。开通协议时非空。
Para:商户需要银行在协议开通结果通知中转发的商户参数,参数规则同支付结果通知命令。字符串,长度不超过128位,开通协议时使用,可空。
LBS:地理位置。格式为“经度|纬度”,经纬度两个参数之间用竖线分开。例如:18.23445|46.000033。可空。
RskLvl:客户风险等级。保留字段。填写商户端客户的风险等级,可空。
参数strGoodsType表示商品类型,其取值如下:
类型编码 |
类型名称 |
支持卡种 |
备注 |
54011600 |
网上支付 |
借记卡、信用卡 |
|
54011610 |
充值缴费 |
借记卡、信用卡 |
|
54011611 |
彩票 |
借记卡、信用卡 |
|
54011612 |
话费 |
借记卡、信用卡 |
|
54011620 |
虚拟商品 |
借记卡、信用卡 |
|
54011621 |
游戏点卡 |
借记卡、信用卡 |
|
540106 |
旅游出行 |
借记卡、信用卡 |
|
54010650 |
酒店 |
借记卡、信用卡 |
|
54010651 |
机票 |
借记卡、信用卡 |
|
540105 |
网上 |
借记卡、信用卡 |
|
54011600 |
服装 |
借记卡、信用卡 |
|
54011630 |
文化教育 |
借记卡、信用卡 |
|
54011631 |
书报杂志 |
借记卡、信用卡 |
|
54011632 |
考试培训 |
借记卡、信用卡 |
|
54011640 |
数码产品 |
借记卡、信用卡 |
|
540107 |
护肤化妆 |
借记卡、信用卡 |
|
54011650 |
母婴用品 |
借记卡、信用卡 |
|
54010111 |
生活日用 |
借记卡、信用卡 |
|
54010112 |
食品 |
借记卡、信用卡 |
|
540102 |
汽车费用 |
借记卡、信用卡 |
|
54010306 |
信用卡还款 |
借记卡 |
此商品类型只允许使用借记卡支付 |
540111 |
保险 |
借记卡、信用卡 |
|
540112 |
家居物品 |
借记卡、信用卡 |
|
540122 |
医疗保健 |
借记卡、信用卡 |
|
540123 |
礼品 |
借记卡、信用卡 |
|
54011660 |
办公设备 |
借记卡、信用卡 |
|
54011670 |
家用电器 |
借记卡、信用卡 |
|
54011680 |
体育用品 |
借记卡、信用卡 |
|
540108 |
娱乐休闲 |
借记卡、信用卡 |
|
54011690 |
网络服务 |
借记卡、信用卡 |
|
54011691 |
收藏爱好 |
借记卡、信用卡 |
|
54011692 |
投资理财 |
借记卡、信用卡 |
|
54011600 |
其他 |
借记卡、信用卡 |
即网上支付 |
商户校验码的内部算法说明:
招行在商户开发包中用genMerchantCode方法封装了商户校验码的生成算法,商户如果不想使用招行提供的封装方法,可以按照下文的描述自行实现校验码的算法逻辑。
商户校验码的格式:“|加密内容|哈希值”。
1、第一步:产生加密内容
加密内容计算规则:RC4加密后进行Base64编码。计算步骤如下:
1) 原始内容:
“随机字符串|收款人<$CmbSplitter$>付款人<$ClientIP$>浏览器IP地址</$ClientIP$><$GoodsType$>商品类型</$GoodsType$><$Reserved$>附加数据</$Reserved$>”
2) 将原始内容以GBK编码转换成二进制内容。
3) 将二进制内容进行RC4加密。RC4加密的Key:将商户秘钥,以ASCII编码转成二进制,再进行MD5运算的结果作为Key。
4) 将加密后的密文进行Base64编码。
5) 将Base64编码结果中的“加号”替换成“星号”
例如,“a3b+D3+2”,需要变成“a3b*D3*2”
2、第二步:计算哈希值
哈希值计算规则:SHA1结果用16进制字符串表示,计算步骤如下:
1) 组装原始内容:“商户秘钥+第一步形成的加密内容+日期+分行号+商户号+订单号+金额+商户附加参数+商户URL”
2) SHA1:将原始内容进行SHA1
3) 将SHA1内容用16进制表示
注意:16进制的字符串,一个字节用两位表示,字节之间不留空格。比如“1AFC33E1…”
3、第三步:生成商户校验码
将第一步和第二步产生的内容拼接成商户校验码,格式:“|加密内容|哈希值”