日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網(wǎng)為廣大站長(zhǎng)提供免費(fèi)收錄網(wǎng)站服務(wù),提交前請(qǐng)做好本站友鏈:【 網(wǎng)站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(wù)(50元/站),

點(diǎn)擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會(huì)員:747

前言

感謝我一位阿里的安全大佬朱哥,在我發(fā)第一篇博客的時(shí)候進(jìn)行指點(diǎn)。 我對(duì)上一篇的不足之處進(jìn)行總結(jié)一下:

  1. 加密過程太過簡(jiǎn)單,我上一篇博客也談到需要改進(jìn),其中包括AppSecret等等也加入到簽名里面。
  2. 時(shí)間戳的問題也要加入進(jìn)去,防止數(shù)據(jù)篡改。時(shí)間戳的問題是防止數(shù)據(jù)重放
  3. 加密算法需要再改進(jìn),MD5需要加點(diǎn)salt等等
  4. 參數(shù)需要排序,這個(gè)有點(diǎn)出入。因?yàn)橐话銇碚f內(nèi)部接口使用類進(jìn)行傳輸參數(shù),可以重寫類的toString()方法來規(guī)范參數(shù)的排序。但是有個(gè)缺陷是:無法通配到不是按對(duì)象來接收的參數(shù),這時(shí)就重寫不了toString了,只能我們手動(dòng)去排序。

show you the code

get處理方法

new 攔截器

import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import com.alibaba.fastjson.JSON;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import JAVAx.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;
import java.util.Map;

public class MyBetterInterceptor implements HandlerInterceptor {

    public static final ThreadLocal<String> local = new ThreadLocal<>();

    public static final ThreadLocal<String> localSign = new ThreadLocal<>();

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String sign = request.getHeader("sign");
        //這里對(duì)應(yīng)appId,外面可以去數(shù)據(jù)庫查Secret
        String appId = request.getHeader("appId");
        if (valid(sign) || valid(appId)) {
            throw new IllegalAccessException("驗(yàn)簽非法");
        }
        String time = request.getHeader("createTime");
        if (valid(time)) {
            throw new IllegalAccessException("時(shí)間戳為空");
        }
        long second = DateUtil.between(new Date(), DateUtil.parse(time), DateUnit.MINUTE);
        if (!(second <= 30 && DateUtil.compare(new Date(), DateUtil.parse(time)) > 0)) {
            throw new IllegalAccessException("非法時(shí)間戳");
        }
        String sb;
        if ("POST".equals(request.getMethod())) {
            //System.out.println("post參數(shù):" + new String(IoUtil.readBytes(request.getInputStream(), false)));
            /*String parameter = new String(IoUtil.readBytes(request.getInputStream(), false));
            sb = ParameterUtil.generateSign(ParameterUtil.postParameter(parameter, time));*/
            local.set(time);
            localSign.set(sign);
            return true;
        } else {
            Map<String, String[]> map = request.getParameterMap();
            System.out.println(JSON.toJSONString(map));
            if (map == null || map.size() == 0) {
                return false;
            }
            sb = ParameterUtil.generateSign(ParameterUtil.getParameter(map, time));
        }

        System.out.println("加密混淆之后的字符串:" + sb);
        //Todo 去數(shù)據(jù)庫查詢appId對(duì)應(yīng)的Sercert,比如這里固定查出來是dajitui
        sb = sb + "dajitui";
        System.out.println("sign:" + SecureUtil.md5(sb));
        if (SecureUtil.md5(sb).equals(sign)) {
            return true;
        }

        return true;
    }

    private boolean valid(String value) {
        return StrUtil.isBlank(value);
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

    }
}

注意點(diǎn)

1.攔截器:我們只能處理get請(qǐng)求的參數(shù),post的話request只能讀取一次,后面無法再讀取一遍,我們使用aop去進(jìn)行驗(yàn)簽。 2.加密算法有所改變,添加了Sercert特有的參數(shù),即使appid被別人拿到了,也沒有多大影響。

加密處理過程

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import com.alibaba.fastjson.JSON;
import org.Apache.commons.codec.digest.DigestUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author M
 */
public class ParameterUtil {
    ParameterUtil() {
    }

    public static Map<String, Object> getParameter(Map<String, String[]> map, String time) {
        if (map == null || map.size() == 0) {
            return new HashMap<>(6);
        }
        Map<String, Object> resultMap = new HashMap<>(map.size());
        map.forEach((k, v) -> {
            if (v.length == 1) {
                resultMap.put(k, v[0]);
            } else {
                resultMap.put(k, new ArrayList<>(Arrays.asList(v)));
            }
        });
        resultMap.put("time",time);
        System.out.println("map:"+ JSON.toJSONString(resultMap));
        return resultMap;
    }

    public static Map<String, Object> postParameter(String msg, String time) {
        if (StrUtil.isBlank(msg)) {
            return new HashMap<>(6);
        }
        JSONArray array=new JSONArray(msg);
        Map<String, Object> resultMap = new HashMap<>(25);
        for(JSONObject object:array.jsonIter()){
            for (String s : object.keySet()) {
                resultMap.put(s, object.get(s));
            }
            resultMap.put("time",time);
        }
        System.out.println("map:"+ JSON.toJSONString(resultMap));
        return resultMap;
    }

    public static final String SEPERATE_CHAR = "#%$";
    public static String generateSign(Map<String, Object> param) {
        Set<String> keys = param.keySet();
        //過濾掉sign,對(duì)key進(jìn)行排序
        List<String> sortedKeys = keys.stream().filter(key -> !Objects.equals(key, "sign")).sorted().collect(Collectors.toList());
        //加上自定義字符串混淆算法
        String calcSign = sortedKeys.stream().map(param::get).map(String::valueOf).collect(Collectors.joining(SEPERATE_CHAR));
        //對(duì)字符串進(jìn)行hash
        calcSign = DigestUtils.sha1Hex(calcSign);
        return calcSign;
    }

    public static void main(String[] args) {
        System.out.println(ParameterUtil.postParameter("{n" +
                "    "status": "0000",n" +
                "    "message": "success",n" +
                "    "data": {n" +
                "        "title": {n" +
                "            "id": "001",n" +
                "            "name" : "白菜"n" +
                "        },n" +
                "        "content": [n" +
                "            {n" +
                "                "id": "001",n" +
                "                "value":"你好 白菜"n" +
                "            },n" +
                "            {n" +
                "                "id": "002",n" +
                "                 "value":"你好 蘿卜" n" +
                "            }n" +
                "        ]n" +
                "    }n" +
                "}",""));
    }

}

其中 postParameter是處理post參數(shù),getParameter處理get參數(shù)轉(zhuǎn)成Map<String,Object>形式。

generateSign才是真正的大頭

public static final String SEPERATE_CHAR = "#%$";
    public static String generateSign(Map<String, Object> param) {
        Set<String> keys = param.keySet();
        //過濾掉sign,對(duì)key進(jìn)行排序
        List<String> sortedKeys = keys.stream().filter(key -> !Objects.equals(key, "sign")).sorted().collect(Collectors.toList());
        //加上自定義字符串混淆算法
        String calcSign = sortedKeys.stream().map(param::get).map(String::valueOf).collect(Collectors.joining(SEPERATE_CHAR));
        //對(duì)字符串進(jìn)行hash
        calcSign = DigestUtils.sha1Hex(calcSign);
        return calcSign;
    }

將key進(jìn)行排序,排序完獲取value,然后它們之間使用特定分隔符分開來,讓別人猜不到我們的加密算法。

最后的sign

		sb = ParameterUtil.generateSign(ParameterUtil.getParameter(map, time));
        System.out.println("加密混淆之后的字符串:" + sb);
        //Todo 去數(shù)據(jù)庫查詢appId對(duì)應(yīng)的Sercert,比如這里固定查出來是dajitui
        sb = sb + "dajitui";
        System.out.println("sign:" + SecureUtil.md5(sb));

特有的根據(jù)appid獲取sercert過程,然后加入再進(jìn)行md5加密。

post處理方法

使用aop+自定義注解

定義一個(gè)注解

@Target({METHOD, FIELD, TYPE})
@Retention(RUNTIME)
public @interface NoParameter {

}

一把梭哈

	@NoParameter
    @PostMapping("/rpc/test1")
    public String a1(@RequestBody Student1 student1){
        System.out.println("list:"+student1);
        return "123";
    }

切面邏輯

import cn.hutool.crypto.SecureUtil;
import com.alibaba.fastjson.JSON;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class TestAspect {

    @Pointcut("@annotation(com.example.demo.NoParameter)")
    public void annotationPoinCut() {

    }

    @Before(value = "annotationPoinCut()")
    public void beforeTest(JoinPoint point) throws IllegalAccessException {
        String args = JSON.toJSONString(point.getArgs());
        String sb = ParameterUtil.generateSign(ParameterUtil.postParameter(args, MyBetterInterceptor.local.get()));
        sb = sb + "dajitui";
        System.out.println("sign:" + SecureUtil.md5(sb));
        if (!SecureUtil.md5(sb).equals(MyBetterInterceptor.localSign.get())) {
            throw new IllegalAccessException("驗(yàn)簽失敗");
        }
        MyBetterInterceptor.local.remove();
        MyBetterInterceptor.localSign.remove();
    }

}

分享到:
標(biāo)簽:接口
用戶無頭像

網(wǎng)友整理

注冊(cè)時(shí)間:

網(wǎng)站:5 個(gè)   小程序:0 個(gè)  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會(huì)員

趕快注冊(cè)賬號(hào),推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨(dú)大挑戰(zhàn)2018-06-03

數(shù)獨(dú)一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學(xué)四六

運(yùn)動(dòng)步數(shù)有氧達(dá)人2018-06-03

記錄運(yùn)動(dòng)步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績(jī)?cè)u(píng)定2018-06-03

通用課目體育訓(xùn)練成績(jī)?cè)u(píng)定