####由于开放型的短信接口受到不明来源的恶意访问 大佬们紧急对整个项目的接口进行加密
原理:密钥+参数生成 md5 签名 客户端保存好密钥即可 之前对接苏宁易购的那个支付平台的时候 也是选择这种方式进行访问加密
1:生成密钥
这个随机定义 例如我选择使用 appId + salt 生成md5 截取前12位作为 指定app应用的密钥 如果发生泄漏 可以通过改变salt 来生成新的密钥
2:客户端密钥 存储
客户端 拿到密钥不能明文存储 例如 12位 可以拆分三段 然后分别进行偏移 这样如果别人要识别 必须反编译源码 并且读懂相关规则
3:签名规则
除开签名以外所有参数 按照排序规则排序 然后拼接上密钥 通过md5 或者类似的算法生成md5签名
4:服务端验证规则
除开签名 也按照客户端同样的排序规则排序 拼接密钥 通过相同的算法生成服务端签名 通过比较客户端签名 和服务端签名 来验证服务是否可靠、
生成签名 方法示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
| #!/usr/bin/env groovy /** groovy 生成md5 签名的算法 * * @author ming * @date 2017-11-15 12:45 */ import java.nio.charset.Charset import java.security.MessageDigest import java.security.NoSuchAlgorithmException import org.apache.commons.codec.binary.Hex;
static void main(String[] args) { Map<String, String[]> map = new HashMap<>() map.put("sign", ["mkasfasfds"] as String[]) map.put("param", ["ming"] as String[]) map.put("b", ["b"] as String[]) map.put("a", ["a"] as String[]) print(getSign("ming", map)) }
/** * 生成签名 * @param accessSecretKey 密钥 * @param parameterMap 参数map 集合 * @author ming * @date 2017-11-15 11:42 */ String getSign(String accessSecretKey, Map<String, String[]> parameterMap) { //拼接参数 StringBuffer allNotEncryptString = new StringBuffer(); String signature = parameterMap.get("sign")[0]; // 获取未加密的请求参数 String notEncryptString = getRequestParameterString(parameterMap); if (notEncryptString == null || notEncryptString.length() == 0) { throw new NullPointerException(" 请求参数拼接为空") } // 组合所有加密的字符穿 allNotEncryptString.append(notEncryptString); allNotEncryptString.append("secret" + accessSecretKey);
// 本地加密 String localSignature = md5(allNotEncryptString.toString(), Charset.forName("UTF-8")).toLowerCase(); return localSignature; }
/** * 取得未加密的请求参数字符串<br/> * 注:1.该字符串的组成规则为: * 1.1 请求参数 'key'+'value'成对 * 1.2 依据字母顺序表:a-->b-->c-->...-->y-->z 对‘请求参数key’排序 * 2.该字符串中不包括signature * */ static String getRequestParameterString(Map<String, String[]> parameterMap) { if (parameterMap == null || parameterMap.size() == 0) { return null; } List<String> parameterNameList = new ArrayList<>(parameterMap.keySet()); // 对请求的key 排序 parameterNameList.sort { a, b -> (a <=> b) }; StringBuffer strBuffer = new StringBuffer(); for (String parameterName : parameterNameList) { //排除签名 if (parameterName == "sign") { continue; } String[] values = parameterMap.get(parameterName); if (values != null) { if (values.length == 1) { strBuffer.append(parameterName + values[0]); } else { //此处规则 省略。。。。 } } }
return strBuffer.toString(); }
/*** * MD5加密 生成32位md5码 * * @param inStr 待加密字符串 * @return 返回32位md5码 */ static String md5(String inStr, Charset charset) { MessageDigest messageDigest = null; try { messageDigest = MessageDigest.getInstance("MD5"); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } if (messageDigest == null) { throw new NullPointerException(); } messageDigest.update(inStr.getBytes(charset)); byte[] digestBytes = messageDigest.digest(); return Hex.encodeHexString(digestBytes); }
|