Web前后端笔记-通过对称加密算法和信息摘要算法防止数据重放
程序员文章站
2024-03-02 23:05:04
...
理论图如下:
这里使用时间戳和随机数和正常提交的表单数据生成MD5摘要,再使用某16位**把MD5进行AES加密,生成128位的数据。然后提交给服务器。
服务器先看提交的时间戳是否在范围内(如2分钟),如果时间非法就直接返回。
然后看各个数据进行某种有规则的算法,生成MD5看看是否与提交的MD5一样,不一样说明是被串改的。
如果MD5一样,对比下数据库中目前时间范围内(如2分钟)是不是二次提交,如果是就拒绝。
将MD5和某16位**进行AES加密,如果和客户端传上来的一样,那么就可以回数据了。
这里本人贴下对应的后端代码:
前端请求如下:
后端代码如下:
@SuppressWarnings("ALL")
@Component
public class XInterceptor extends HandlerInterceptorAdapter {
@Autowired
AuthXXXXService authService;
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
if(httpServletRequest.getMethod().equals("GET")){
String url = httpServletRequest.getRequestURI();
String contextPath = httpServletRequest.getServletPath();
String para = httpServletRequest.getQueryString();
Enumeration<String> parameterNames = httpServletRequest.getParameterNames();
Map<String, String[]> parameterMap = httpServletRequest.getParameterMap();
//参数是否正常
if(!parameterMap.containsKey("timestamp") || !parameterMap.containsKey("signature") || !parameterMap.containsKey("shield")){
httpServletResponse.sendError(VoXXXXEm.PARA_ERROR.getCode());
return false;
}
//先检测签名是否过期 30s内不会过期
Long timestamp = Long.valueOf(parameterMap.get("timestamp")[0]);
Long currentStamp = System.currentTimeMillis();
if(timestamp < (currentStamp - 30 * 1000)){
httpServletResponse.sendError(VoEm.TIMEOUT.getCode());
return false;
}
//检查签名是否合法
String originStr = "";
for(Enumeration key = parameterNames ; parameterNames.hasMoreElements();){
String KeyPara = key.nextElement().toString();
if(KeyPara.equals("signature") || KeyPara.equals("shield"))
continue;
originStr += parameterMap.get(KeyPara)[0] + "$";
}
originStr = originStr.substring(0, originStr.length() - 1);
String md5Str = MD5Utils.generateMD5(originStr);
//验证签名
if(!md5Str.equals(parameterMap.get("signature")[0])){
httpServletResponse.sendError(VoXXXXEm.SIGN_ERROR.getCode());
return false;
}
//禁止重放
if(authService.isSignatureInResetMap(md5Str)){
httpServletResponse.sendError(VoXXXXEm.REST_ERROR.getCode());
return false;
}
//验证护盾
String originShield = parameterMap.get("shield")[0];
//key值为签名的前16位
String decrypt = AESUtil.decrypt(originShield, parameterMap.get("signature")[0].substring(0, 16));
if(!parameterMap.get("signature")[0].equals(decrypt)){
httpServletResponse.sendError(VoXXXXEm.SHIELD_ERROR.getCode());
return false;
}
//加入到禁止重放里面
authService.addResetMap(md5Str, timestamp);
//System.out.println("over");
}
else{
}
return true;
}
@Override
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
}
}
这里提下
AuthXXXXService存储了MD5的相关数据。这里在Spring Boot中有个调度线程池
如下,每隔一段数据就清空下: