keyword:伪装支付,伪造支付,假回调支付
原理
1.微信支付成功后,微信会给业务服务器发送回调通知,回调内容为一系列 参数的键值对参数按照key=value的格式,并按照参数名ASCII字典序排序生成字符串,然后用商户私钥对其进行签名,如MD5,并将签名撇接到字符串后,然后以XML方式发送给业务服务器,如果秘钥泄露,他人可任意伪造回调数据进行假通知,在业务服务器(1.没有更进一步判断IP是否来自微信服务器,2没有进行主动查询)的情况下订单支付成功
XML格式如下
<xml>
<appid><![CDATA[wx7702adbodfgfr]]></appid>
<bank_type><![CDATA[CFT]]></bank_type>
<cash_fee><![CDATA[1]]></cash_fee>
<fee_type><![CDATA[CNY]]></fee_type>
<is_subscribe><![CDATA[Y]]></is_subscribe>
<mch_id><![CDATA[14859555676]]></mch_id>
<nonce_str><![CDATA[5cc7f45fc4693]]></nonce_str>
<openid><![CDATA[o57o9wTaynF4KQLCKFkKU_bQwpQE]]></openid>
<out_trade_no><![CDATA[CZ1455646546556]]></out_trade_no>
<result_code><![CDATA[SUCCESS]]></result_code>
<return_code><![CDATA[SUCCESS]]></return_code>
<sign><![CDATA[31B9853EABE111E5EB34549AE7353D1]]></sign>
<time_end><![CDATA[20190430150824]]></time_end>
<total_fee>1</total_fee>
<trade_type><![CDATA[JSAPI]]></trade_type>
<transaction_id><![CDATA[4200000300201904302784014299]]></transaction_id>
</xml>
其中sign即为签名值
2.验签
服务器收到回调通知后,将除sign以外的参数进行拼接,形如
appid=wx7702adb1a1bfe&bank_type=CFT&cash_fee=1&fee_type=CNY&is_subscribe=Y&mch_id=1485955572&nonce_str=5cc7f45fc4693&openid=o57o9wTaynF4KQLCKFkKU_bQwpQE&out_trade_no=CZ1455646546556&result_code=SUCCESS&return_code=SUCCESS&time_end=20190430150824&total_fee=1&trade_type=JSAPI&transaction_id=4200000300201904302784014299
然后用微信商户提供的保存在自己服务器上的的私钥对其进行签名,将其与回调通知里的sign进行比对,如果一样,则服务器任务支付成功,执行支付后的业务逻辑(所以商户私钥一点不要泄露,尽量避免直接写在代码里)
伪装回调
条件:
必须知道商户私钥key
服务器回调地址
实现:
1.在业务平台进行下单,获取订单号,修改out_trade_no为此单号,修改支付金额等参数
2.生成签名
#1.对参数按照key=value的格式,并按照参数名ASCII字典序排序生成字符串:
appid=wx7702adba1bfe&bank_type=CFT&cash_fee=1&fee_type=CNY&is_subscribe=Y&mch_id=14859&nonce_str=5cc7f45fc4693&openid=o57o9wTaynF4KQLCKFkKU_bQwpQE&out_trade_no=CZ1455646546556&result_code=SUCCESS&return_code=SUCCESS&time_end=20190430150824&total_fee=1&trade_type=JSAPI&transaction_id=4200000300201904302784014299
#2.连接商户key:
appid=wx7702adba1bfe&bank_type=CFT&cash_fee=1&fee_type=CNY&is_subscribe=Y&mch_id=148595&nonce_str=5cc7f45fc4693&openid=o57o9wTaynF4KQLCKFkKU_bQwpQE&out_trade_no=CZ1455646546556&result_code=SUCCESS&return_code=SUCCESS&time_end=20190430150824&total_fee=1&trade_type=JSAPI&transaction_id=4200000300201904302784014299&key=key
这里可以用微信提供的支付接口签名校验工具生成
https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=20_1
3.发送回调
以POST方式携带生成的XML格式参数请求回调地址(XML可能需要压缩去除空格回车)即可支付成功
防止
1私钥不要泄露,避免直接写在代码里
2收到回调通知后,与订单里的支付金额,时间等进行验证,
3收到回调通知后调用主动查询订单接口进行查询确认是否支付成功
4.将 notify_url 复杂化
5.使用HTTPS
6.绑定通知服务器 ip
附微信回调IP白名单
商户侧对商户回调通知功能开通白名单网段:
101.226.103.0/25、140.207.54.0/25、103.7.30.0/25、183.3.234.0/25、58.251.80.0/25
说明:
上海电信出口网段101.226.103.0/25
上海联通出口网段140.207.54.0/25
深圳电信出口网段183.3.234.0/25
深圳联通出口网段58.251.80.0/25
香港出口网段103.7.30.0/25
注意:深圳的出口为新增,商户侧需要新开防火墙
官方地址:
https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=23_2