[Spring Cloud] (7)gateway防重放拦截器

文章目录

  • 简述
    • 本文涉及代码已开源
    • Fir Cloud 完整项目
    • 防重放
      • 防重放必要性:
      • 防重放机制作用:
  • 整体效果
    • 后端进行处理
  • 后端
    • 增加防重放开关配置
    • 签名密钥 工具类
    • 防重放拦截器
  • 前端
    • 被防重放拦截
    • 增加防重放开关配置
    • 请求头增加防重放签名处理
    • 防重放验证处理函数
    • base64加密生成签名
    • 请求头信息增加

简述

本文涉及代码已开源

本文网关gateway,微服务,vue已开源到gitee
杉极简 / gateway网关阶段学习
https://gitee.com/dong-puen/gateway-stages

Fir Cloud 完整项目

该内容完整项目如下
Fir Cloud v1.0.0
https://gitee.com/dong-puen/fir-cloud
https://github.com/firLucky/fir-cloud
在这里插入图片描述

防重放

防重放攻击的必要性主要来自于网络安全中的一个核心原则:确保数据的完整性、机密性和不可否认性。重放攻击是一种常见的安全威胁,它利用网络通信的漏洞来重新发送之前捕获的通信数据,以欺骗系统执行未授权的操作。

防重放必要性:

  1. 数据完整性:防止攻击者通过重放攻击修改或替换数据,确保数据在传输过程中未被篡改。
  2. 防止身份盗用:防止攻击者利用截获的认证信息冒充合法用户,从而访问受保护的资源。
  3. 保护交易:在金融交易和电子商务中,防止攻击者通过重放交易来欺诈。
  4. 遵守法规:某些行业法规要求实施防重放机制,以符合数据保护和网络安全的法律要求。
  5. 维护信任:通过保护系统免受重放攻击,维护用户和系统之间的信任关系。

防重放机制作用:

  1. 验证时间戳:通过在消息中包含时间戳,并确保消息在合理的时间窗口内被接收,可以防止旧消息被重放。
  2. 数字签名:使用数字签名来验证消息的发送者和内容,确保消息未被篡改,并且发送者的身份得到验证。
  3. 应用层检查:在应用层进行额外的逻辑检查,例如验证用户的状态或会话,以防止重放攻击。
  4. 日志和监控:记录和监控网络活动,以便在发生重放攻击时能够快速检测和响应。

通过实施防重放机制,可以显著提高系统的安全性,保护关键数据和操作免受未授权的访问和篡改。在设计系统时,应考虑潜在的重放攻击,并采取适当的措施来防范。

整体效果

前端如果没有进行防重放信息处理,则会被直接拦截。

后端进行处理

image.png

后端

增加防重放开关配置

  # 防重放replay: true
    /*** 防重放攻击*/private boolean replay;

image.png
image.png

签名密钥 工具类

package com.fir.gateway.utils;import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Base64;/*** 签名密钥 工具类* * @author fir*/
public class SignatureUtils {/*** 解密前端防重放校验的签名密钥(失败未验证)** @param signature 签名密钥* @param secretKey 加密密钥* @return 返回解密结果*/public static String decryptSignature(String signature, String secretKey) {try {// 使用HMAC-SHA256算法Mac sha256Hmac = Mac.getInstance("HmacSHA256");SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getBytes(StandardCharsets.UTF_8), "HmacSHA256");sha256Hmac.init(secretKeySpec);// 对签名进行Base64解码byte[] signatureBytes = Base64.getDecoder().decode(signature);// 进行解密操作byte[] decryptedBytes = sha256Hmac.doFinal(signatureBytes);// 将解密结果转为字符串String decryptedSignature = new String(decryptedBytes, StandardCharsets.UTF_8);return decryptedSignature;} catch (Exception e) {e.printStackTrace();return null;}}/*** 解密前端防重放校验的签名密钥** @param signature 签名密钥* @return 返回解密结果*/public static String decryptSignatureBase64(String signature) {try {// 对签名进行Base64解码byte[] signatureBytes = Base64.getDecoder().decode(signature);// 将解密结果转为字符串return new String(signatureBytes, StandardCharsets.UTF_8);} catch (Exception e) {e.printStackTrace();return null;}}
}

防重放拦截器

package com.fir.gateway.filter.request;import com.alibaba.fastjson.JSONObject;
import com.fir.gateway.config.GlobalConfig;
import com.fir.gateway.config.result.AjaxResult;
import com.fir.gateway.config.result.AjaxStatus;
import com.fir.gateway.dto.ReplayAttackInfo;
import com.fir.gateway.utils.SignatureUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;import javax.annotation.Resource;
import java.nio.charset.StandardCharsets;
import java.util.*;/*** 防重放攻击-请求拦截器** @author fir*/
@Component
@Slf4j
public class ReplayAttackFilter implements GlobalFilter, Ordered {/*** 网关参数配置*/@Resourceprivate GlobalConfig globalConfig;/*** 5 * 60 * 1000 表示5分钟的间隔,用于防重放的间隔之中*/private static final long TIMESTAMP_VALID_TIME = 5 * 60 * 1000;private final Set<String> usedNonceSet = Collections.synchronizedSet(new HashSet<>());/*** 每分钟执行一次*/@Scheduled(cron = "0 * * * * *")public void clearUsedNonceSet() {usedNonceSet.clear();}@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {log.info("防重放攻击验证:start");boolean replay = globalConfig.isReplay();if(replay) {// 白名单路由判断ServerHttpRequest request = exchange.getRequest();String path = request.getPath().toString();List<String> whiteUrls = globalConfig.getWhiteUrls();if(whiteUrls.contains(path)){log.info("防重放攻击验证:true,白名单");return chain.filter(exchange);}// 从请求头中获取Nonce和TimestampString nonce = exchange.getRequest().getHeaders().getFirst("n");String timestamp = exchange.getRequest().getHeaders().getFirst("t");String s = exchange.getRequest().getHeaders().getFirst("s");// 验证Nonce和Timestamp是否合法boolean validateKey = validateNonceAndTimestamp(nonce, timestamp, s);if (validateKey) {// 如果合法,则放行请求log.info("防重放攻击验证:true");} else {log.info("防重放攻击验证:false");// 如果不合法,则返回错误响应ServerHttpResponse response = exchange.getResponse();// 自定义返回体描述AjaxResult error = AjaxResult.error(AjaxStatus.ANTI_REPLAY_VERIFY_FAILED);String resData = JSONObject.toJSONString(error);byte[] responseBody = resData.getBytes(StandardCharsets.UTF_8);response.getHeaders().setContentLength(responseBody.length);response.getHeaders().setContentType(MediaType.APPLICATION_JSON);return response.writeWith(Mono.just(response.bufferFactory().wrap(responseBody)));}}else {log.info("防重放攻击验证:true,验证已关闭");}return chain.filter(exchange);}@Overridepublic int getOrder() {// 设置过滤器的优先级return -200;}/*** 根据请求时间戳,与请求签名密钥,判断请求是否是合法的** @param nonce 请求签名密钥* @param timestamp 请求时间戳* @return 是否合法*/private boolean validateNonceAndTimestamp(String nonce, String timestamp, String s) {// 判断Nonce和Timestamp是否为空if (nonce == null || timestamp == null) {log.error("防重放攻击验证:非法请求,无请求时间戳");return false;}// 验证Nonce是否已经使用过if (usedNonceSet.contains(nonce)) {log.error("防重放攻击验证:请求签名已使用");return false;} else {// 将本次的请求签名记录,用于下次判断是否有相同的请求签名usedNonceSet.add(nonce);}// 判断事件戳与数据签名是否相同String str = SignatureUtils.decryptSignatureBase64(nonce);ReplayAttackInfo replayAttackInfo = JSONObject.parseObject(str, ReplayAttackInfo.class);String t = replayAttackInfo != null ? replayAttackInfo.getT() : null;if (StringUtils.isBlank(t) || !timestamp.equals(t)){log.error("防重放攻击验证:非法请求,请求时间非法");return false;}// 验证Timestamp是否在合理时间范围内long timeStampValue;try {timeStampValue = Long.parseLong(timestamp);} catch (NumberFormatException e) {log.error("防重放攻击验证:非法请求,请求时间错误");return false;}long currentTime = System.currentTimeMillis();// 判断请求是是否是在n分钟之前请求的boolean a = timeStampValue >= currentTime - TIMESTAMP_VALID_TIME;// 判断请求是是否是在n分钟后前请求的boolean b = timeStampValue <= currentTime + TIMESTAMP_VALID_TIME;boolean c = a && b;if (!c){log.info("防重放攻击验证:请求过期");}return c;}
}

前端

被防重放拦截

image.png
增加nonce(签名),t(时间戳)。

增加防重放开关配置

// 防重放
const replay = true;

image.png

请求头增加防重放签名处理

gatewayRequest中增加

            // 防重放请求通过信息if (replay) {this.replayAttack(request);}

image.png

防重放验证处理函数

    //************************************防重放-start/*** 防重放验证** @param config Axios请求的配置对象*/replayAttack(config) {let params = config.params;let reqData = config.params;let t = new Date().getTime();if (t) {config.headers.t = tif (reqData == null) {params = {'t': t,}} else {// params = JSON.parse(reqData)params["t"] = t;}const data = JSON.stringify(params);config.headers.n = this.gBase(data);}},//************************************防重放-end

base64加密生成签名

    /*** base64加密* @param data data 待加密数据*/gBase(data) {return CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(data));},

请求头信息增加

此时请求头中会增加两个信息,一个是时间戳,一个是签名。后端此时就会验证信息是否合法,合法则放行。
image.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/11182.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

打造清洁宜居家园保护自然生态环境,基于YOLOv5全系列【n/s/m/l/x】参数模型开发构建自然生态场景下违规违法垃圾倾倒检测识别系统

自然生态环境&#xff0c;作为我们人类赖以生存的家园&#xff0c;其健康与否直接关系到我们的生活质量。然而&#xff0c;近年来&#xff0c;一些不法分子为了个人私利&#xff0c;在河边、路边等公共区域肆意倾倒垃圾&#xff0c;严重破坏了环境的健康与平衡。这种行为不仅损…

18.04版本的ubuntu没有连接网络的图标(坑人版)

以下更新内核别看&#xff0c;因为后面安装驱动报一堆错误!!! 不升级内核成功方法跳转连接&#xff1a;https://blog.csdn.net/weixin_53765004/article/details/138771613?csdn_share_tail%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%2213877…

单调栈问题

原理 单调栈的核心原理是&#xff1a;在栈内保持元素的单调性&#xff08;递增或递减&#xff09; 单调递增栈&#xff1a; 用于处理“下一个更小的元素”问题。当新元素比栈顶元素小或等于时&#xff0c;直接入栈&#xff1b;否则&#xff0c;一直从栈顶弹出元素&#xff0c…

OBS直播二次开发_OBS直播软件介绍

OBS工作室版 免费且开源的用于视频录制以及直播串流的软件。 下载以在Windows, Mac以及Linux上简单且快速的开始串流。 功能 实时高性能的视频/音频捕捉与混合,以及无限的场景模式使您可以通过自定义实现无缝转换。为视频源设计的滤镜例如图片蒙版,色彩校正,色度/色彩键控…

软件体系结构风格

目录 一、定义 二、.经典软件体系结构风格&#xff1a; 1.管道和过滤器 2.数据抽象和面向对象系统 3.基于事件系统&#xff08;隐式调用&#xff09; 4.分层系统 5.仓库 6.C2风格 7.C/S 8.三层C/S 9.B/S 题&#xff1a; 一、定义 软件体系机构风格是描述某一特定应用…

通过内网穿透实现远程访问个人电脑资源详细过程(免费)(NatApp + Tomcat)

目录 1. 什么是内网穿透 2. 内网穿透软件 3. NatApp配置 4. 启动NatApp 5. 通过内网穿透免费部署我们的springboot项目 通过内网穿透可以实现远程通过网络访问电脑的资源&#xff0c;本文主要讲述通过内网穿透实现远程访问个人电脑静态资源的访问&#xff0c;下一章节将讲…

C语言/数据解构——(随即链表的复制)

一.前言 嗨嗨嗨&#xff0c;大家好久不见。已经有好几天没更新了。今天我们就分享一道链表题吧——随即链表的复制https://leetcode.cn/problems/copy-list-with-random-pointer废话不多说&#xff0c;让我们直接开始今天的题目分享吧。 二.正文 1.1题目描述 他和单链表不同…

华为OD机试 - 求幸存数之和(Java 2024 C卷 100分)

华为OD机试 2024C卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试&#xff08;JAVA&#xff09;真题&#xff08;A卷B卷C卷&#xff09;》。 刷的越多&#xff0c;抽中的概率越大&#xff0c;每一题都有详细的答题思路、详细的代码注释、样例测试…

机器学习面试篇

如何理解机器学习数据集的概念 数据集是机器学习的基础&#xff0c;它包括了用于训练和测试模型所需的数据。数据集通常以矩阵的形式存在&#xff0c;其中每一行代表一个样本&#xff08;或实例&#xff09;&#xff0c;每一列代表一个特征&#xff08;或属性&#xff09;。…

JVM从1%到99%【精选】-类加载子系统

目录 1.类的生命周期 1.加载 2.连接 3.初始化 2.类的加载器 1.类加载器的分类 2.双亲委派机制 3.面试题&#xff1a;类的双亲委派机制是什么&#xff1f; 4.打破双亲委派机制 1.类的生命周期 类加载过程&#xff1a;加载、链接&#xff08;验证、准备、解析&a…

数据与结构--堆

堆 堆的概念 堆&#xff1a;如果有一个关键码的集合K{k0,k1,k2,…,kn-1}&#xff0c;把它的所有元素按完全二叉树的顺序存储方式存储在一个一维数组中&#xff0c;并满足ki<k2i1且ki<k2i2&#xff08;或满足ki>k2i1且ki>k2i2&#xff09;&#xff0c;其中i0,1,2,…

深度缓冲技术在AI去衣中的神奇作用

引言&#xff1a; 随着人工智能技术的飞速发展&#xff0c;其在图形处理和视觉领域的应用日益增多。AI去衣技术便是其中一个颇具争议但又技术上引人入胜的话题。今天&#xff0c;我们将深入探讨一项关键技术——深度缓冲&#xff08;Depth Buffering&#xff09;&#xff0c;它…

SpringAI 技术解析

1. 发展历史 SpringAI 的发展历史可以追溯到对 Spring 框架的扩展和改进&#xff0c;以支持人工智能相关的功能。随着人工智能技术的快速发展&#xff0c;SpringAI 逐渐成为 Spring 生态系统中的一个重要组成部分&#xff0c;为开发者提供了便捷、灵活的解决方案。 项目的灵感来…

如何用opencv去掉单元格的边框线,以提高Tesseract识别率?

在OpenCV中处理从表格切割下来的图片&#xff0c;并去掉单元格的边框线&#xff0c;以提升Tesseract的识别准确率&#xff0c;确实是一个具有挑战性的任务。在这种情况下&#xff0c;我们需要采取一种策略来预处理图像&#xff0c;使得数字与背景之间的对比度增强&#xff0c;同…

数据缓存,可以尝试RocksDB了

shigen坚持更新文章的博客写手&#xff0c;擅长Java、python、vue、shell等编程语言和各种应用程序、脚本的开发。记录成长&#xff0c;分享认知&#xff0c;留住感动。 个人IP&#xff1a;shigen shigen在最近的学习中&#xff0c;接触到了一款新的缓存数据库RocksDB&#xff…

NodeJS编写后端接口

技术栈 1.express&#xff1a;Express是一个简洁而灵活的node.js Web应用框架, 提供了一系列强大特性帮助你创建 各种 Web 应用&#xff0c;和丰富的 HTTP 工具&#xff0c;使用 Express 可以快速地搭建一个完整功能的网站。 2.mysql&#xff1a;用于操作MySQL数据库 3.bod…

【Linux】centos7安装软件(rpm、yum、编译安装),补充:查找命令的相关文件路径,yum安装mysql

【Linux】技术上&#xff0c;Linux是内核。而术语上&#xff0c;我们通常说的Linux是完整的操作系统&#xff0c;其实称为"Linux发行版"&#xff0c;是将Linux内核和应用系统打包&#xff0c;由不同的发行家族发行了不同版本。Linux发行版众多&#xff0c;主要有RedH…

职校智慧校园现状及问题分析

各大中职院校及高职院校是校园信息化的先行者和开拓者&#xff0c;很早就开始注重信息化基础设施建设和信息化人文素养的提升。在过去几年里&#xff0c;随着国家大力发展与扶植职校教育&#xff0c;学校投入相当的经费进行了校园信息通信网络、计算机等基础硬件设备建设&#…

CLion 写 Rust 报Project directory `/Users/.../rsheets` does not exist.

每次打开CLion都会看到像下面这样的报错&#xff0c;Project directory /Users/.../rsheets does not exist.&#xff0c;虽然不会影响你写代码&#xff0c;但每次看到还是不舒服&#xff0c;所以研究一下怎么解决。 原因是这样的&#xff0c;每当我们创建一个 Cargo 项目&…

PDF Squeezer for Mac,让PDF压缩更高效

还在为PDF文件过大而烦恼吗&#xff1f;试试PDF Squeezer for Mac吧&#xff01;它拥有强大的压缩功能&#xff0c;可以快速将PDF文件压缩至更小的体积&#xff0c;让你的文件传输更快捷。同时&#xff0c;它还支持多种压缩方式&#xff0c;满足你的不同需求。赶快下载体验吧&a…