生成的sign出现偶发性的签名验证失败问题排查

Posted by 石福鹏 on 2020-11-24

最近做了一个微信企业付款,即微信企业账户给用户下发红包的功能,从测试开始就出现偶发性的报SIGN_ERROR签名错误,因为自己的项目比较多,就让同时帮忙debug排查了,排查的结果就是没问题,红包发放正常。
但是一上测试,就会偶发;

发现问题

无奈之下,我就把每次请求的request、response都打印出来了,通过微信支付接口签名校验工具测试了下,发现sign并不一致

image-20201124155931683

发现一个问题,后面都一样,前面少0了,多验证几个签名错误的情况看看:

哦豁,还真是,对验证几个证实了这个问题,随意去检查生成sign的工具类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public static String createSign(Map<String, String> parameters, String key) throws Exception {

ArrayList<String> keylist = new ArrayList<>(parameters.keySet());
Collections.sort(keylist);
StringBuilder sb = new StringBuilder();
for (int i = 0; i < keylist.size(); i++) {
if ("".equals(parameters.get(keylist.get(i)))) {
continue;
}
sb.append(keylist.get(i)).append("=").append(parameters.get(keylist.get(i)));
if (i < keylist.size() - 1) {
sb.append("&");
}
}
sb = sb.append("&key=" + key);
String sign = MD5Util.MD5(sb.toString()).toUpperCase();
return sign;
}

发现问题

看了下,签名肯定没问题了,有问题就出在MD5咯?但是第一感觉是MD5会有啥问题,乍一看是没问题,很多人也是这么做的,但是如果得到的md5结果是以0开头的,那结果就悲剧了,转化为数值类型的时候会将开头的0丢弃,所以造成结果和sign不一致的情况出现!

如下就是我用的工具类

1
2
3
4
5
6
7
8
9
10
11
12
13
static public String MD5(String str) {
MessageDigest digest;
try {
// 生成一个MD5加密计算摘要
digest = MessageDigest.getInstance("MD5");
// 计算md5函数
digest.update(str.getBytes());
return new BigInteger(1, digest.digest()).toString(16);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
return null;
}
}

解决问题

改进后的

1
2
3
4
5
6
7
8
9
static public String MD5(String str) throws Exception {
java.security.MessageDigest md = MessageDigest.getInstance("MD5");
byte[] array = md.digest(str.getBytes("UTF-8"));
StringBuilder sb = new StringBuilder();
for (byte item : array) {
sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));
}
return sb.toString().toUpperCase();
}