防止重复请求 get 和post

之前用md5 sha256等加密算法
约束了get请求中防止参数被其他人篡改

但是如果黑客多次请求 该接口  无法被防止
那么需要在get 请求中假如timestamp
get 和 post的区别
get 和post  没有长度限制   长度限制时浏览器决定的

参数位置都一样  get 可以放url中 也可以放body中
                    post  可以放body中 也可以放url中
只要是http  都不安全
区别是 get 和post  get/uri  http/1.1    post/uri http/1.1


tcp/ip 协议是可靠的  可以发送大数据  可以发送小数据
但是浏览器仅仅支持地址栏最大发送1024kb 长度限制  
但是不是说get 请求有长度限制

 

 

 

controll中 最好不要将map 当接受参数  因为参数数量不确定

package com.msb.api;
import cn.hutool.core.convert.Convert;
import com.msb.api.posttest.SignDTO;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
/**
 * @author lcc
 * @version V1.0
 * @Package com.msb.api.posttest
 * @date 2022/5/9 21:12
 */
@RestController
@RequestMapping("/api-safe")
public class ApiSafeController {
    @RequestMapping("/test")
    public String test(){
        return "test";
    }
    
    @RequestMapping("/get-test")
    public String getTest(String appId, String name, String sign, long timeStamp, HttpServletRequest request){
        HashMap<String, Object> hashMap = new HashMap<>();
      /* 参数写死
       hashMap.put("appId",appId);
        hashMap.put("name",name);
        hashMap.put("timeStamp",timeStamp);*/
      /*下面会把sign 当参数传入 会获取新的sign  肯定会不想同*/
        Enumeration<String> parameterNames = request.getParameterNames();
        while (parameterNames.hasMoreElements()){
            String s = parameterNames.nextElement();//获取请求参数的名字
            System.out.print(s+" ");
            String parameter = request.getParameter(s);//获取请求参数的值
            System.out.print(parameter+" ");
           hashMap.put(s, parameter);
        }
        /*让接口在有效期内访问
        long time = System.currentTimeMillis() - timeStamp;
        if(time>1000*30){
            return "接口过期了";
            //throw TimeException("接口过期了");
        }*/
        System.out.println("传过来的额sign:"+sign);
        String s = CheckUtils.generatorSign(hashMap);
        System.out.println("生成的s"+s);
        if(s.equals(sign)){//如果前段传过来的sign 签名(经过md5加密过后)后端再来对传输过来的数据进行加密  然后对比看得出来的值是否相等
            return "通过";
        }else {
            return "不通过";
        }
    
    }
    
    
    @PostMapping("/postTest")
    public String postTest(@RequestBody SignDTO signDTO){
        //JSONObject jsonObject = JSONUtil.parseObj(signDTO);
       // System.out.println(jsonObject);
        //参数转map
        Map<String, Object> stringObjectMap = Convert.toMap(String.class, Object.class, signDTO);
        //排序
        Map<String, Object> stringObjectMapSort = CheckUtils.sortMapByKey(stringObjectMap);
        System.out.println(stringObjectMapSort);
        //map 生成sign
        String signServer = CheckUtils.generatorSign(stringObjectMapSort);//因为这里的generatorSign 把sign 移除了 
        //客户端传来的sign
        String signClient = (String)stringObjectMap.get("sign");
        System.out.println(signClient);
        //判断签名
        if(signServer.equals(signClient)){//如果前段传过来的sign 签名(经过md5加密过后)后端再来对传输过来的数据进行加密  然后对比看得出来的值是否相等
            return "通过";
        }else {
            return "不通过";
        }
    
    
       
    }
    
}
package com.msb.api;

import com.msb.MD5Util;

import java.util.*;
import java.util.function.BiFunction;

/**
 * @author lcc
 * @version V1.0
 * @Package com.msb.api
 * @date 2022/5/9 21:20
 */
public class CheckUtils {
    //appSecret和appId 一一对应
    public static  String AppSecret="aaa";
    //根据map 生成签名  为了排序
    public static String generatorSign(Map<String,Object> map){
        //先移除sign
        map.remove("sign");
        //排序
        Map<String, Object> stringObjectMap = sortMapByKey(map);
        //转格式
        Set<Map.Entry<String, Object>> entries = stringObjectMap.entrySet();
        StringBuffer bf = new StringBuffer();
        for (Map.Entry<String, Object> entry : entries) {
            bf.append(entry.getKey()+":"+entry.getValue()+",");
        }
       // bf.subSequence(0, bf.length()-1);
        //组装secret 在参数后面添加 secret
        bf.append("secret:").append(AppSecret);
        //生成签名
        System.out.println(bf);
        System.out.println(MD5Util.md5(bf.toString()));
        
        return MD5Util.md5(bf.toString());//MD5 算法不可逆 生成的
        /*可以将生成的sign 放入redis 中  加入过期时间  如果在时间内 这个人多次访问  只要在redis 中存在这个md5 存在的key  
        * 那么就拒绝访问
        * */
    }
    
    public static Map<String,Object> sortMapByKey(Map<String,Object> map){
        TreeMap<String, Object> treeMap = new TreeMap<>(new MyMapComparator());
    
        treeMap.putAll(map);
    
        return treeMap;
    }
    
    private static class MyMapComparator implements Comparator<String> {
        @Override
        public int compare(String o1, String o2) {
            return o1.compareTo(o2);
        }
    }
    
    public static void main(String[] args) {
        HashMap<String, Object> hashMap = new HashMap<>();
      /*  hashMap.put("ap",1);
        hashMap.put("zp",2);
        hashMap.put("cp",3);
        Map<String, Object> stringObjectMap = sortMapByKey(hashMap);
        System.out.println(stringObjectMap);*/
        hashMap.put("appId",1);
        hashMap.put("name",2);
        //hashMap.put("timeStamp", 1650490843064L);
       // hashMap.put("sign","sddd59fa505b7bd2a352f179d58c2eb90");
        String s = generatorSign(hashMap);
        System.out.println(s);//a3337ee5d708e41ac38bd0d88561b95f
    }
    
   
    
    
}
package com.msb.api.posttest;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @author lcc
 * @version V1.0
 * @Package com.msb.api.posttest
 * @date 2022/5/10 10:10
 */
@AllArgsConstructor
@NoArgsConstructor
@Data
public class SignDTO {
    
    private String appId;
    
    private String name;
    
    private String sign;
    
}

 

posted @ 2022-05-10 10:57  花心大萝卜li  阅读(352)  评论(0)    收藏  举报