如何使用拦截器实现接口防篡改

17 篇文章 0 订阅

分析

  • 使用签名的机制通过拦截器实现防篡改(避免请求中途被黑客修改了请求参数值而请求接口)
  • 前端用和后端一样的算法,将请求参数通过算法生成一个sign
  • 后端用和前端一样的算法,也传过来的参数算法生成一个sign
  • 比对前端和后端的sign是否一致,若不一致则是请求中途中被篡改过,则此次访问接口请求将会报错
    在这里插入图片描述

前端部分

请求函数

 ajaxGet("/test2", {a:1, b:2,c:3, d:4}, function (data) {
            console.log(data);
        })
  • ajaxGet函数
//异步请求 get方式
function ajaxGet(url, params, success, fail) {
    ajaxRequest(url, "GET", params, success, fail);
}
  • ajaxRequest函数
//异步请求
function ajaxRequest(url,type, param, success, fail){
    //通过js操作将加密之后的签名手动添加到参数中去
    param.sign = getSignString(param);  //使用逻辑处理
    // {a:1, b:2,c:3, d:4, sign:xxx}
    var token = getToken();
    $.ajax({
        type: type,

        url: domainUrl + url,
        data: param,
        dataType: 'json',
        beforeSend:function(xhr){
            xhr.setRequestHeader("token",token);
        },
        success:function (data) {
            if(!data){
                popup("请求异常");
            }else{
                if(data.code == 200){
                    if(success){
                        success(data);
                    }
                }else if(data.code == 401){
                    //未登录
                    Cookies.remove("token");
                    Cookies.remove("user");
                    $(".login-out").css("display", "")
                    $(".login_info").css("display", "none")
                    popup("请先登录");

                }else{
                    if(fail){
                        fail(data);
                    }else{
                        popup(data.msg);
                    }
                }
            }
        },
        error:function () {
            popup("网络不通,请联系管理员~");
        }

    })
}

算法函数(重点)

  • 引入md5.js文件,即可使用md5加密,可通过我博客资源下寻找并下载此js文件
  • getSignString函数
  • 将要请求的参数拼接起来(如:a=1&b=2&c=3&d=4),然后通过MD5加密生成sign
//{a:1,b:2,c:3,d:4}
function getSignString(param) {
    var sdic=Object.keys(param).sort();
    var signStr = "";
    //[a,b,c,d]
    for(var i in sdic){
        if(i == 0){
            //a=1
            signStr +=sdic[i]+"="+param[sdic[i]];
        }else{

            signStr +="&"+sdic[i]+"="+param[sdic[i]];
        }
    }
    console.log(signStr);//a=1&b=2&c=3&d=4
    console.log(hex_md5(signStr));
    return hex_md5(signStr).toUpperCase();
}

后端部分

MD5工具类


public class Md5Utils {
	
	/**
     * @Description: 生成MD5
     * @param message
     * @return
     */
    public static String getMD5(String message) {
        String md5 = "";
        try {
            MessageDigest md = MessageDigest.getInstance("MD5"); // 创建一个md5算法对象
            byte[] messageByte = message.getBytes("UTF-8");
            byte[] md5Byte = md.digest(messageByte); // 获得MD5字节数组,16*8=128位
            md5 = bytesToHex(md5Byte); // 转换为16进制字符串
        } catch (Exception e) {
            e.printStackTrace();
        }
        return md5;
    }
    
    /**
     * @Description: 二进制转十六进制
     * @param bytes
     * @return
     */
    private static String bytesToHex(byte[] bytes) {
        StringBuffer hexStr = new StringBuffer();
        int num;
        for (int i = 0; i < bytes.length; i++) {
            num = bytes[i];
            if (num < 0) {
                num += 256;
            }
            if (num < 16) {
                hexStr.append("0");
            }
            hexStr.append(Integer.toHexString(num));
        }
        return hexStr.toString().toUpperCase();
    }
    
    /**
     * 
     * @Description: 签名:请求参数排序并后面补充key值,最后进行MD5加密,返回大写结果
     * @param params 参数内容
     * @return
     */

    /**
     * {
     *     a:   "1"
     *     b:   "2"
     *     c:   "3"
     *     d:   "4"
     *
     * }
     */
    public static String signatures(Map<String, Object> params){
        String signatures = "";
        try {
            List<String> paramsStr = new ArrayList<String>();
            for (String key1 : params.keySet()) {
                if(null != key1 && !"".equals(key1)){
                    paramsStr.add(key1);
                }
            }
            Collections.sort(paramsStr);
            StringBuilder sbff = new StringBuilder();
            for (String kk : paramsStr) {
                String value = params.get(kk).toString();
                if ("".equals(sbff.toString())) {
                    sbff.append(kk + "=" + value);
                } else {
                    sbff.append("&" + kk + "=" + value);
                }
            }
            //加上key值
            signatures = getMD5(sbff.toString()).toUpperCase();
        }catch(Exception e) {
            e.printStackTrace();
        }
        return signatures;
    }
}

定义拦截器

/**
 * 签名拦截(防篡改)
 */
public class SignInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if(!(handler instanceof HandlerMethod)){
            return  true;
        }

        /**
         * {
         *     a:   "1"
         *     b:   "2"
         *     c:   "3"
         *     d:   "4"
         *
         * }
         */
        //签名验证
        Map<String, String[]> map = request.getParameterMap();
        Map<String, Object> param = new HashMap<>();
        for (String s : map.keySet()) {
            if("sign".equalsIgnoreCase(s)){
                continue;
            }
            param.put(s, arrayToString(map.get(s)));
        }
        String signatures = Md5Utils.signatures(param);  //sign_server
        String sign = request.getParameter("sign");  //sign_client
        if(sign == null || !sign.equalsIgnoreCase(signatures)){
            response.setContentType("text/json;charset=UTF-8");
            response.getWriter().write(JSON.toJSONString(new JsonResult(501,"签名校验失败","不好意思咯")));
            return false;
        }
        return true;
    }


    private String arrayToString(String [] array){

        StringBuilder sb = new StringBuilder(10);
        for (String s : array) {
            sb.append(s);
        }
        return sb.toString();
    }
}
  • 记得定义完拦截器要去配置~(此处就不做演示了)

测试接口

@RestController
public class TestController {

    @GetMapping("/test2")
    public Object test2(int a,int b,int c,int d,String sign){
            return JsonResult.success(Arrays.asList(a,b,c,d,sign));
    }
}

效果演示

成功

在这里插入图片描述

失败

  • 我把成功的签名值不变,改变了参数值然后请求,则报错~

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值