app开放接口签名设计与实现

来源:互联网 发布:ubuntu16.04 网络映射 编辑:程序博客网 时间:2024/04/28 21:56

只要接口暴露在外网,就避免不了安全问题。如果让接口裸奔,其他人只要知道接口地址和参数就可以调用,那简直就是灾难。试想有一个发送注册验证码的接口,如果仅仅知道接口地址和参数(手机号)就可以调用,那短信接口早被人盗刷不知道多少了。

理想情况下,我们只希望我们的接口被我们自己的客户端去调用,

那么问题来了,我们如何验证调用者身份呢,如何防止参数被篡改呢?如何防止别人盗刷我们的接口来攻击我们呢?

常见的做法就是给接口加签名。

原理是:每次请求的时候根据请求的参数加上时间戳,根据约定好的规则和秘钥生成一个签名。

服务端接收到请求后,先校验签名的合法性,不合法视为非法请求,拦截掉;签名合法,才处理请求。因为其他人不知道我们的签名生成算法和秘钥,所以没法伪造请求去盗刷我们的接口,即便监听到请求,然后篡改了参数,但是因为签名是和参数绑定的,所以改变了参数,签名就非法了,篡改参数就没有意义了。

签名过程:

1:将所有参数放进一个数组中,数组中用 属性=值的形式将参数都放进数组中。

例如有3个参数access_token=eb1982a9508c4fe2b2b78233331cd498,nickName=jessica,timestamp=1507859403954,放进数组中为["access_token=eb1982a9508c4fe2b2b78233331cd498","timestamp=1507859403954","nickName=jessica"]

2:将数组按字典排序

排序后为[access_token=eb1982a9508c4fe2b2b78233331cd498, nickName=jessica, timestamp=1507859403954]

3:迭代排序后的数组,将数组里的元素拼接成一个字符串

access_token=eb1982a9508c4fe2b2b78233331cd498nickName=jessicatimestamp=1507859403954

4:将这个字符串用MD5加密

5:将加密后的字符串+盐用SHA512加密成128位的签名。

然后服务端在拦截器里加校验签名,没加签名和签名非法的直接拦截掉。

获得请求的参数的代码:

/** * 获得请求的参数 * @param request */private String[] showParams(HttpServletRequest request,String timestamp) {int parmeterSize=request.getParameterMap().size();if(parmeterSize>0){String []parms=new String[request.getParameterMap().size()];Enumeration paramNames = request.getParameterNames();if(request.getParameterMap().size()==0){return null;}int i=0;while (paramNames.hasMoreElements()) {String paramName = (String) paramNames.nextElement();String[] paramValues = request.getParameterValues(paramName);if (paramValues.length == 1) {String paramValue = paramValues[0];if (paramValue.length() != 0) {parms[i]=paramName+"="+paramValue;i++;}}}return parms;}}
校验签名的方法:

   private static final String salt="1234567890...abcdefghigklmpopqrstuvwxyz";         /** * 校验签名 * @param timestamp * @param signature * @param params * @return */public static boolean checkSignature(long timestamp,String signature,String params[]){if (timestamp == 0 || signature == null||params==null) {return false;}long nowTime = System.currentTimeMillis();// 接口请求的时间在600秒钟之前的直接抛弃if ((nowTime - timestamp) > 600000) {return false;}// 将方法的参数按字典排序,然后按字典排序将它们加起来的字符串+盐按SHA512加密,和签名作对比Arrays.sort(params);int length=params.length;String signStr="";if (params != null &&length>0) {StringBuilder sb=new StringBuilder(length);for (int i = 0; i < length; i++) {if(!StringUtil.isBlank(params[i])){sb.append(params[i]);}}signStr=MD5Helper.encrypt(sb.toString());if (signature.equals(EncryptionUtil.SHA512((signStr+salt)))) {return true;}}return false;}

阅读全文
1 0
原创粉丝点击