项目场景:
开发服务对接微信公众平台,服务器配置以及接收消息事件
问题描述:
[添加链接描述](https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Access_Overview.html),最后有示例代码下载, 根据示例代码Java版本中的以下代码进行签名校验,一直提示“签名验证错误”,以下为校验方法:
/**
* 验证URL
* @param msgSignature 签名串,对应URL参数的msg_signature
* @param timeStamp 时间戳,对应URL参数的timestamp
* @param nonce 随机串,对应URL参数的nonce
* @param echoStr 随机串,对应URL参数的echostr
*
* @return 解密之后的echostr
* @throws AesException 执行失败,请查看该异常的错误码和具体的错误信息
*/
public String verifyUrl(String msgSignature, String timeStamp, String nonce, String echoStr)
throws AesException {
String signature = SHA1.getSHA1(token, timeStamp, nonce, echoStr);
if (!signature.equals(msgSignature)) {
throw new AesException(AesException.ValidateSignatureError);
}
String result = decrypt(echoStr);
return result;
}
/**
* 用SHA1算法生成安全签名
* @param token 票据
* @param timestamp 时间戳
* @param nonce 随机字符串
* @param encrypt 密文
* @return 安全签名
* @throws AesException
*/
public static String getSHA1(String token, String timestamp, String nonce, String encrypt) throws AesException
{
try {
String[] array = new String[] { token, timestamp, nonce, encrypt };
StringBuffer sb = new StringBuffer();
// 字符串排序
Arrays.sort(array);
for (int i = 0; i < 4; i++) {
sb.append(array[i]);
}
String str = sb.toString();
// SHA1签名生成
MessageDigest md = MessageDigest.getInstance("SHA-1");
md.update(str.getBytes());
byte[] digest = md.digest();
StringBuffer hexstr = new StringBuffer();
String shaHex = "";
for (int i = 0; i < digest.length; i++) {
shaHex = Integer.toHexString(digest[i] & 0xFF);
if (shaHex.length() < 2) {
hexstr.append(0);
}
hexstr.append(shaHex);
}
return hexstr.toString();
} catch (Exception e) {
e.printStackTrace();
throw new AesException(AesException.ComputeSignatureError);
}
}
原因分析:
其中有两个问题
文档描述1)将token、timestamp、nonce三个参数进行字典序排序 2)将三个参数字符串拼接成一个字符串进行sha1加密 3)开发者获得加密后的字符串可与signature对比,标识该请求来源于微信,但是代码里多使用了echoStr,这里导致所有地方调用计算签名全部算错了
verifyUrl方法最后将echoStr解密返回,实际上文档要求将echoStr原封不动返回,因为echoStr微信本身也没有做加密
以上问题在企业微信版的处理中没有问题,企业微信校验签名确实使用到了echoStr
解决方案:
修改getSHA1方法,最后一个参数不参与签名的计算,修改verifyUrl方法echoStr参数不进行解密,否则会报错
评论区