一 防篡改是什么?

防篡改(英语:Tamper resistance)是指通过包装、系统或其他物理措施抗击产品正常用户的篡改(tamper,故意引发故障或造成破坏)的行为。

二 防重放是什么?

入侵者 C 可以从网络上截获 A 发给 B 的报文。C 并不需要破译这个报文(因为这
可能很花很多时间)而可以直接把这个由 A 加密的报文发送给 B,使 B 误认为 C 就是 A。然后
B 就向伪装是 A 的 C 发送许多本来应当发送给 A 的报文

三 防篡改和防重放的解决方式

可以通过时间戳,将时间戳放在header头中进行处理
    通过时间戳 + sign签名处理,通过将报文参数进行相应的md5进行签名处理,同时将时间戳和sign放在header中,网关进行相应的验签证明请求的合法性
    通过时间戳+随机数(norce)+sign签名的方式进行处理
    流程如下:
   

四 代码实现

1.Filter实现


/*** 安全基线拦截器:* 防重放、防篡改*/
@Component
public class CosSecurityFilter extends ZuulFilter {private final Logger log = LoggerFactory.getLogger(CosSecurityFilter.class);@Resourceprivate CosSecurityProperties cosSecurityProperties;@Resourceprivate CosSecurityUtil cosSecurityUtil;@Resourceprivate AntPathMatcher antPathMatcher;@Overridepublic String filterType() {return FilterConstants.PRE_TYPE;}/*** 拦截顺序,越小越优先** @return*/@Overridepublic int filterOrder() {return -9;}@Overridepublic boolean shouldFilter() {RequestContext ctx = RequestContext.getCurrentContext();if (BooleanUtil.isTrue(cosSecurityProperties.getEnable())&& !ctx.getBoolean("transmit")) {return true;} else {log.debug("【安全基线】未开启");return false;}}/*** 如果安全校验不通过,请求上下文中会有isSecurityPass;* isSecurityPass为true,代表安全校验通过* isSecurityPass为false,代表安全校验不通过*/@Overridepublic Object run() {log.info("---CosSecurityFilter---");RequestContext ctx = RequestContext.getCurrentContext();HttpServletRequest request = ctx.getRequest();String uri = request.getRequestURI();String sign = request.getHeader(CosSecurityConstants.HEADER_SIGN);String timestamp = request.getHeader(CosSecurityConstants.HEADER_TIMESTAMP);String nonce = request.getHeader(CosSecurityConstants.HEADER_NONCE);String clientVersion = request.getHeader(CosSecurityConstants.HEADER_VERSION);String method = request.getMethod();String contentType = request.getContentType();try {//url白名单List<String> ignoreUrlList = cosSecurityProperties.getIgnoreUrlList();if (CollectionUtil.isNotEmpty(ignoreUrlList)) {for (String ignoreUrl : ignoreUrlList) {if (antPathMatcher.match(uri, ignoreUrl)) {return null;}}}switch (method) {case ServletUtil.METHOD_POST://application/json才校验签名if (contentType.contains(MediaType.APPLICATION_JSON_VALUE)) {// 版本号不符合条件if (StrUtil.isNotEmpty(clientVersion) && (!Pattern.matches(CosSecurityConstants.PATTERN_VERSION, clientVersion)|| AppUtil.compareVersion(clientVersion, CosSecurityConstants.CONFIG_BASE_VERSION_VALUE) < 0)) {if (cosSecurityProperties.getIsValidVersion()){//如果开启版本号校验并且版本号为空或者不符合条件throw new BusinessException(ExceptionEnum.VERSION_LOW.getCode(), ExceptionEnum.VERSION_LOW.getErrMsg());} else {//如果不开启版本号校验,并且版本在11以下 不验证签名return null;}}BodyReaderHttpServletRequestWrapper httpServletRequestWrapper = new BodyReaderHttpServletRequestWrapper(request);//校验签名cosSecurityUtil.validPostSign(sign, Long.valueOf(timestamp), nonce, httpServletRequestWrapper);ctx.setRequest(httpServletRequestWrapper);//校验超时时间cosSecurityUtil.validTimestamp(timestamp);//校验随机数cosSecurityUtil.validAndSaveNonce(nonce, request);}break;case ServletUtil.METHOD_GET:// GET请求不作处理break;default:break;}ctx.set(CosSecurityConstants.KEY_IS_SECURITY_PASS, true);} catch (BusinessException e) {log.error("【安全请求校验】校验不通过,uri=[{}],timestamp=[{}],nonce=[{}],sign=[{}],errorMessage=[{}]", uri, timestamp, nonce, sign, e.getMessage());log.error("error:",e);ctx.setSendZuulResponse(false);ctx.setResponseStatusCode(HttpStatus.INTERNAL_SERVER_ERROR.value());ResultMessage result = new ResultMessage(false, e.getCode(), e.getErrMsg());ctx.getResponse().setCharacterEncoding("UTF-8");ctx.getResponse().setContentType("application/json; charset=utf-8");ctx.setResponseBody(JSON.toJSONString(result, SerializerFeature.BrowserCompatible));ctx.set(CosSecurityConstants.KEY_IS_SECURITY_PASS, false);} catch (Exception e) {log.error("【安全请求校验】校验失败,uri=[{}],timestamp=[{}],nonce=[{}],sign=[{}],errorMessage=[{}]", uri, timestamp, nonce, sign, e.getMessage());log.error("error:",e);ctx.setSendZuulResponse(false);ctx.setResponseStatusCode(HttpStatus.INTERNAL_SERVER_ERROR.value());ResultMessage result = new ResultMessage(false, ExceptionEnum.SIGN_INVALID.getCode(), ExceptionEnum.SIGN_INVALID.getErrMsg());ctx.getResponse().setCharacterEncoding("UTF-8");ctx.getResponse().setContentType("application/json; charset=utf-8");ctx.setResponseBody(JSON.toJSONString(result, SerializerFeature.BrowserCompatible));ctx.set(CosSecurityConstants.KEY_IS_SECURITY_PASS, false);}return null;}}

2.工具类实现


@Component
public class CosSecurityUtil {private final Logger log = LoggerFactory.getLogger(CosSecurityUtil.class);@Resourceprivate CosSecurityProperties cosSecurityProperties;@Resourceprivate StringRedisTemplate stringRedisTemplate;@Autowiredprivate RedissonClient redissonClient;/*** 校验请求有效时间** @param time* @return*/public void validTimestamp(String time) throws Exception {if (StrUtil.isEmpty(time)) {throw new BusinessException(ExceptionEnum.TIMESTAMP_INVALID.getCode(), ExceptionEnum.TIMESTAMP_INVALID.getErrMsg());}if (!Pattern.matches(CosSecurityConstants.PATTERN_TIMESTAMP, time)) {throw new BusinessException(ExceptionEnum.TIMESTAMP_INVALID.getCode(), ExceptionEnum.TIMESTAMP_INVALID.getErrMsg());}Long timestamp = Long.valueOf(time);//服务器UTC时间LocalDateTime utcLocalDateTime = Instant.now().atZone(ZoneId.of("UTC")).toLocalDateTime();LocalDateTime severalMinutesBefore = LocalDateTimeUtil.offset(utcLocalDateTime, -10L, ChronoUnit.MINUTES);LocalDateTime severalMinutesAfter = LocalDateTimeUtil.offset(utcLocalDateTime, 10L, ChronoUnit.MINUTES);if (timestamp > LocalDateTimeUtil.toEpochMilli(severalMinutesBefore) && timestamp < LocalDateTimeUtil.toEpochMilli(severalMinutesAfter)) {//do nothing} else {//签名超时throw new BusinessException(ExceptionEnum.SIGN_TIMEOUT.getCode(), ExceptionEnum.SIGN_TIMEOUT.getErrMsg());}}/*** 校验nonce,并保存至redis中** @param nonce* @param request* @return*/public void validAndSaveNonce(String nonce, HttpServletRequest request) throws Exception {if (StrUtil.isEmpty(nonce)) {throw new BusinessException(ExceptionEnum.NONCE_INVALID.getCode(), ExceptionEnum.NONCE_INVALID.getErrMsg());}if (!Pattern.matches(CosSecurityConstants.PATTERN_NONCE, nonce)) {throw new BusinessException(ExceptionEnum.NONCE_INVALID.getCode(), ExceptionEnum.NONCE_INVALID.getErrMsg());}String remoteHost = request.getRemoteHost();String method = request.getMethod();String requestUrl = request.getRequestURL().toString();JSONObject nonceRedisValue = new JSONObject();nonceRedisValue.put("remoteHost", remoteHost);nonceRedisValue.put("method", method);nonceRedisValue.put("requestUrl", requestUrl);String nonceRedisKey = CosSecurityConstants.PREFIX_NONCE_KEY + nonce;Boolean hasKey = stringRedisTemplate.hasKey(nonceRedisKey);if (null != hasKey && hasKey) {throw new BusinessException(ExceptionEnum.REQUEST_REPEAT.getCode(), ExceptionEnum.REQUEST_REPEAT.getErrMsg());}RBucket<String> nonceBucket = redissonClient.getBucket(nonceRedisKey);boolean isSuccess = nonceBucket.trySet(nonceRedisValue.toJSONString(), 10L, TimeUnit.MINUTES);if (!isSuccess) {throw new BusinessException(ExceptionEnum.REQUEST_REPEAT.getCode(), ExceptionEnum.REQUEST_REPEAT.getErrMsg());}}/*** 校验POST请求的sign** @param sign* @param timestamp* @param nonce* @throws Exception*/public void validPostSign(String sign, Long timestamp, String nonce, BodyReaderHttpServletRequestWrapper request) throws Exception {if (StrUtil.isEmpty(sign)) {throw new BusinessException(ExceptionEnum.SIGN_INVALID.getCode(), ExceptionEnum.SIGN_INVALID.getErrMsg());}if (!Pattern.matches(CosSecurityConstants.PATTERN_SIGN, sign)) {throw new BusinessException(ExceptionEnum.SIGN_INVALID.getCode(), ExceptionEnum.SIGN_INVALID.getErrMsg());}//取请求body体的md5摘要String reqBody = request.getBodyString();log.info("【安全基线-POST请求签名校验】requestBody=[{}]", reqBody);String body = DigestUtils.md5Hex(reqBody);//计算规则:sign=md5(timestamp+nonce+body+key)String signString = "timestamp=" + timestamp + "&nonce=" + nonce + "&body=" + body +"&key=" + cosSecurityProperties.getSecurityCode();log.info("验签字符串拼接结果为:{}",signString);String serverSign = DigestUtils.md5Hex(signString);log.info("【安全基线-POST请求签名校验】前端sign=[{}],后端计算body=[{}],后端sign=[{}]", sign, body, serverSign);if (!StrUtil.equals(sign.toLowerCase(), serverSign.toLowerCase())) {throw new BusinessException(ExceptionEnum.SIGN_INVALID.getCode(), ExceptionEnum.SIGN_INVALID.getErrMsg());}}public static void main(String[] args){String reqBody = "";String body = DigestUtils.md5Hex(reqBody);LocalDateTime utcLocalDateTime = Instant.now().atZone(ZoneId.of("UTC")).toLocalDateTime();Long timestamp = LocalDateTimeUtil.toEpochMilli(utcLocalDateTime);System.out.println(timestamp);String nonce = "eb8f198d36b3edcb913ade2506707631";//计算规则:sign=md5(timestamp+nonce+body+key)String signString = "timestamp=" + timestamp + "&nonce=" + nonce + "&body=" + body +"&key=" + "RETAILCLOUD@HUA123";String serverSign = DigestUtils.md5Hex(signString);System.out.println(serverSign);}
}

gateway防篡改和防重放代码实现相关推荐

  1. 一文看懂设备指纹如何防篡改、防劫持

    一定程度上,设备指纹之于人的重要意义不亚于身分证. 为什么这么说? 大多数人可能都有过这样的经历: 刷短视频时,只要我们点赞了某个视频,那么下一次再刷视频时,系统就会推荐更多类似的视频:当你在某个购物 ...

  2. post 防篡改_Cookie防篡改机制

    一.为什么Cookie需要防篡改 为什么要做Cookie防篡改,一个重要原因是 Cookie中存储有判断当前登陆用户会话信息(Session)的会话票据-SessionID和一些用户信息. 当发起一个 ...

  3. linux系统防篡改,网站防篡改脚本

    这是我生产中所用的防篡改脚本需要的拿走点赞. 扫描定义的数组目录的所有文件的MD5值,然后在用下面个脚本对比 1.2.2.4 扫描deploy目录的md5值脚本 [root@localhost scr ...

  4. API的防篡改和防重放机制

    接口安全问题 请求身份是否合法? 请求参数是否被篡改? 请求是否唯一? AccessKey&SecretKey (开放平台) 请求身份 为开发者分配AccessKey(开发者标识,确保唯一)和 ...

  5. 服务器自带的防篡改,防篡改系统

    产品优势 一.技术先进 采用先进的文件驱动防篡改技术,稳定.可靠.高效.兼容性高. 新一代内核驱动及文件保护,确保防护功能不被恶意攻击或者非法终止 支持大规模连续篡改攻击保护. 二.保护全面 实时动态 ...

  6. WAF和网络防火墙、网页防篡改、IPS三者的区别

    Web应用的日益普及和Web攻击的与日俱增,让Web安全问题备受关注.但对于正常流量中的危险分子,传统的安全产品根本无能为力,此时,我们该靠什么来保护Web应用?Web应用防火墙(WAF)无疑是最佳之 ...

  7. gateway+vue实现防接口重放、防篡改

    这里写目录标题 引言 解决思路 核心代码 前端代码 增加请求头 工具类 后端代码 全局过滤器 配置类 工具类 请求封装类 mdb加密工具类 校验类 防重放验证类 防篡改验证 主要花精力的地方 需要知道 ...

  8. php重放,Api 接口安全-防篡改,防重放理解总结

    防篡改 为什么要防篡改 http 是一种无状态的协议, 服务端并不知道客户端发送的请求是否合法, 也并不知道请求中的参数是否正确 举个栗子, 现在有个充值的接口, 调用给用户对应的余额 http:// ...

  9. springboot 和 js (vue) 实现SM3加密 防篡改

    springboot 和 js (vue) 实现SM3加密 防篡改 一.以下是对引入SM3进行说明 1.首先导入jar <dependency><groupId>org.bou ...

最新文章

  1. 08-dispatch_apply
  2. ubuntu下用命令行安装Qt
  3. python数据动画_[转载]Maya使用Python获取动画每帧的rotation数据
  4. 辽宁大学计算机专业接收调剂,目前有计算机专业调剂通知的学校,不断更新—3月26日更新,新增辽宁大学等...
  5. x什么意思c语言新闻app啊我et,C语言笔试题目
  6. java poi导出Excel表格超大数据量解决方案
  7. Python标准库11 多进程探索 (multiprocessing包)
  8. 手机APP测试流程方法
  9. 微信小程序:分包大小超过限制
  10. vue项目运行npm install报错
  11. uc浏览器登录报错50001解决方案,登录失败,请重试50001
  12. 螳螂有6条腿C语言,一只蜈蚣40只脚,一只螳螂有6只脚,现有蜈蚣和螳螂共35只,合计脚822只,蜈蚣和螳螂各多少只?...
  13. opencv-3.0.0-beta和opencv2版本的区别
  14. 金蝶迷你版云服务器没有响应,金蝶迷你版登录提示云服务器异常
  15. 交互设计师为什么需要具备产品思维
  16. Mysql 学习教程
  17. mysql 快速造数据sql
  18. 测试胎儿体重计算器软件,胎儿体重计算器
  19. js(76-108)
  20. ## 看看sass和less会遇到的问题吧

热门文章

  1. 更新一期:智科人第一次参加2022节能减排大赛的经验加前端开发的app源代码(资料区下载)
  2. 汉字的内码和区位码与显示汉字原理
  3. moodle 3.11平台安装与迁移
  4. 启动crystal reports工具比较慢
  5. eclipse中集成tomcat8
  6. Unity3D教程宝典之插件篇:Unity3D插件详细评测及教学下载
  7. 2022计算机考研全改408,2022计算机408考研大纲
  8. kitti数据集链接
  9. SNMP简单网络管理协议总结
  10. c 中空格的asc码表_C语言常用转义字符表 和 ASCII码表完整版