API接口签名验证_MD5加密出现不同结果的解决方法

项目场景:

系统在提供接口给第三方系统使用时,通常为了安全性会做接口加密。
设计原则:使用HTTPS安全协议 或 传输内容使用非对称加密,这里采用后者。

问题描述:

在对参数进行加密,生成sign时,相同的参数两次加密的结果不一样。

加密规则:

public class SignUtil {

    /**
     * Md5加密方式生成sign
     * 参数名ASCII码从小到大排序(字典序)
     *
     * @param parameters 参数名-值
     * @param secretKey  秘钥
     * @return sign 签名
     */
    public static String createSign(SortedMap<String, Object> parameters, String secretKey) {
        StringBuffer sb = new StringBuffer();
        // 所有参与传参的参数按照ASCLL排序(升序)
        Set es = parameters.entrySet();
        Iterator it = es.iterator();
        while (it.hasNext()) {
            Map.Entry entry = (Map.Entry) it.next();
            String k = (String) entry.getKey();
            Object v = entry.getValue();
            // 字符拼接
            if (null != v && !StringUtils.EMPTY.equals(v) && !"signature".equals(k)) {
                sb.append(k + "=" + v + "&");
            }
        }
        // 末尾拼接密钥
        String md5 = sb.append(secretKey).toString();
        return MD5(md5).toUpperCase();
    }

    /**
     * MD5加密
     *
     * @param content
     * @return
     */
    public static final String MD5(String content) {
        char[] md5String = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};

        try {
            byte[] btInput = content.getBytes();
            MessageDigest mdInst = MessageDigest.getInstance("MD5");
            mdInst.update(btInput);
            byte[] md = mdInst.digest();
            int j = md.length;
            char[] str = new char[j * 2];
            int k = 0;

            for (int i = 0; i < j; ++i) {
                byte byte0 = md[i];
                str[k++] = md5String[byte0 >>> 4 & 15];
                str[k++] = md5String[byte0 & 15];
            }

            return new String(str);
        } catch (Exception var10) {
            return null;
        }
    }
}

原因分析及解决方案:

1.拼接出来的字符串不一致
测试时,在加密前将要加密的字符串打印出来比较,发现两次字符串一致。

2.编码问题
加密时,两次的默认编码不一致。
在上述加上默认编码:byte[] btInput = content.getBytes("utf-8");,问题解决。

接口验签流程

简单实现:
1.接口调用方和接口提供方约定好统一的参数加密算法。
2.接口调用方在调用时把加密后的signature放在参数中去请求接口。
3.判断时间戳有效期。
4.将参数用约定号的加密算法进行加密,与参数中的signature进行比较,一致则调用接口。

// 签名密钥
String secretKey = PropertiesUtil.getProperties("api.properties", "secretKey");
// 生成签名
Map params = JSONObject.parseObject(jsonStr, Map.class);
SortedMap<String, Object> temps = new TreeMap<>();
temps.putAll(params);
String sign = SignUtil.createSign(temps, secretKey);
// 签名验证
if (!signature.equals(sign)) {
	return "签名不一致!";
}
return service.getInfo(param1, param2);
posted on 2022-06-09 23:18  猫的树kireCat  阅读(601)  评论(0编辑  收藏  举报