接口安全--http数字签名

2/22/2017来源:ASP.NET技巧人气:1788

为了保证http请求数据的安全性和防篡改性。我们通常要对请求参数进行一些加密。 加密规则可以根据双方接口协商定义。这里举一个常用的加密协议例子。

1. sign加密协议

接口协议中通常会提供一个 appKey作为唯一的标识。 appSecret作为接入密钥。 例如:appkey=hh appSecret=39ertfefdsg406c7c36592d42022aaecc 请求路径 http://www.example.com/login 请求参数 appKey hh 合作方平台标识 username 用户名 passWord 密码 time Unix时间戳(10位) sign 签名串

2. 加密要求

将筛选的参数按照第一个字符的键值ASCII码递增排序(字母升序排序),如果遇到相同字符则按照第二个字符的键值ASCII码递增排序,以此类推。 将排序后的参数与其对应值,组合成“参数=参数值”的格式,并且把这些参数用&字符连接起来,此时生成的字符串为待签名字符串 生成签名 sign = md5(待签名字符串) 示例 例如: sign = md5(待签串) 参数表为: appKey=hs, username=lzl, password=88fsdfgsff8fd9ssg99 time=1432432234 待签名字符串为(取排序后的结果,这里key不参与排序): appKey=hh&password=HG20170113140431206&time=1423212323&key=密钥

3. 处理流程

我们根据加密要求,把要传送的字段进行排序和MD5加密。将加密后的结果和传输的字段一并送过去。 appKey=hh&password=HG20170113140431206&time=1423212323&key=密钥&sign=签名串。 验证方式: 如何保证这条http请求能够正常相应数据呢?提供接口方,也是根据传输的字段进行排序和MD5加密。将加密后的结果verifySign与sign进行 比较。如果相同,就说明是一个正常的请求。反之,就是以非法请求。 代码示例:

public class MD5Utils { /** * 参数签名加密 * @param parameters * @param secret * @return */ public static String signRequest(TreeMap<String,String> parameters,String secret,String charset){ TreeMap<String, String> treeMap = new TreeMap<>(new Comparator<String>() { @Override public int compare(String o1, String o2) { return o1.compareTo(o2); } }); treeMap = (TreeMap<String, String>) parameters; System.out.PRintln("升序排序结果:"+treeMap); StringBuffer sb = new StringBuffer(); //把map中的集合拼接成字符串 for(Map.Entry<String, String> entry:treeMap.entrySet()){ String key = entry.getKey(); Object value = entry.getValue(); sb.append(key).append("=").append(value).append("&"); } sb.append("key").append("=").append(secret); System.out.println("拼接后的字符:"+sb.toString()); //进行MD5加密 String sign = DigestUtils.md5Hex(getContentBytes(sb.toString(), charset)); System.out.println("加密后的签名:"+sign); return sign; } /** * @param content * @param charset * @return * @throws SignatureException * @throws UnsupportedEncodingException */ private static byte[] getContentBytes(String content, String charset) { if (charset == null || "".equals(charset)) { return content.getBytes(); } try { return content.getBytes(charset); } catch (UnsupportedEncodingException e) { throw new RuntimeException("MD5签名过程中出现错误,指定的编码集不对,您目前指定的编码集是:" + charset); } } public static void main(String[] args) { TreeMap<String,String> treeMap = new TreeMap<>(); treeMap.put("appKey", "hh"); treeMap.put("username", "1335288"); treeMap.put("password", "435rewt32423ewt4325terw"); treeMap.put("time", String.valueOf(System.currentTimeMillis()/1000)); String key = "密钥"; MD5Utils.signRequest(treeMap,key,"utf-8"); } }