Spring Cloud Gateway防重放攻击实现

news/2024/7/6 1:42:32

文章目录

  • 一、实现防重放攻击的方案
  • 二、使用Nonce和Timestamp进行防重放攻击


一、实现防重放攻击的方案

  • 使用Nonce和Timestamp: 在请求中加入一个随机数(Nonce)和当前时间戳,服务端收到请求后验证该请求的Nonce是否已经使用过并且请求的时间戳是否在合理时间范围内。

  • 使用Token: 在服务端生成一个唯一的Token,并在响应中返回给客户端,客户端在下一次请求中需要带上该Token,服务端收到请求后验证该Token是否已经使用过。

  • 使用Redis 或者 JWT: 将每次请求的信息存储在Redis中或者JWT中,服务端收到请求后验证该请求是否重复。

二、使用Nonce和Timestamp进行防重放攻击

具体实现方式如下:

import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
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 java.util.Collections;
import java.util.HashSet;
import java.util.Set;

/**
 * @author Clang
 * @version 1.0
 * @date 2023/1/17 14:01
 */
@Component
@Slf4j
public class ReplayAttackFilter implements GlobalFilter, Ordered {

    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();
    }

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // 从请求头中获取Nonce和Timestamp
        String nonce = exchange.getRequest().getHeaders().getFirst("nonce");
        String timestamp = exchange.getRequest().getHeaders().getFirst("Timestamp");
        // 验证Nonce和Timestamp是否合法
        if (validateNonceAndTimestamp(nonce, timestamp)) {
            // 如果合法,则放行请求
            return chain.filter(exchange);
        } else {
            // 如果不合法,则返回错误响应
            ServerHttpResponse response = exchange.getResponse();
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            return response.setComplete();
        }
    }

    @Override
    public int getOrder() {
        // 设置过滤器的优先级
        return -1;
    }

    private boolean validateNonceAndTimestamp(String nonce, String timestamp) {
        // 判断Nonce和Timestamp是否为空
        if (nonce == null || timestamp == null) {
            return false;
        }

        // 验证Nonce是否已经使用过
        if (usedNonceSet.contains(nonce)) {
            return false;
        } else {
            usedNonceSet.add(nonce);
        }

        // 验证Timestamp是否在合理时间范围内
        long timeStampValue;
        try {
            timeStampValue = Long.parseLong(timestamp);
        } catch (NumberFormatException e) {
            return false;
        }

        long currentTime = System.currentTimeMillis();
        if (timeStampValue < currentTime - TIMESTAMP_VALID_TIME || timeStampValue > currentTime + TIMESTAMP_VALID_TIME) {
            return false;
        }

        return true;
    }
}

usedNonceSet是一个Set类型的变量,用来存储已经使用过的Nonce值。在上面的代码中,在验证请求的Nonce是否合法时,会先判断Nonce是否已经在usedNonceSet中出现过,如果出现过,则认为该请求是重放攻击,返回错误响应。

这个usedNonceSet变量应该是在类的变量里定义并初始化的,并且需要注意的是,这个set要确保线程安全,在不同的线程中能够正确的读写。

private final Set<String> usedNonceSet = Collections.synchronizedSet(new HashSet<>());

这里把usedNonceSet 使用了Collections.synchronizedSet 包装,可以保证线程安全。

需要注意的是,这种方法的限制是有时效性的,在一定时间内重复使用的nonce是不会被拦截的。因此需要定期清空这个set,或者使用其他方式存储已使用过的nonce。

   /**
     * 每分钟执行一次
     */
    @Scheduled(cron = "0 * * * * *")
    public void clearUsedNonceSet() {
        usedNonceSet.clear();
    }

需要注意的是,这些方法都只是简单的清空set,更好的做法是能够记录每个nonce使用的时间,在超过时效性之后删除。

private static final long TIMESTAMP_VALID_TIME = 5 * 60 * 1000;

这里定义了TIMESTAMP_VALID_TIME为5分钟,即请求时间戳的有效时间范围为当前时间前5分钟和当前时间后5分钟。

需要注意的是,这个TIMESTAMP_VALID_TIME是需要根据具体场景和需求来确定的,如果设置过大,则会增加重放攻击的风险,如果设置过小,则会增加误拦截的风险。

以上方法都是定时清空usedNonceSet的方法,可以根据业务需求和资源限制进行选择。

提示:更多内容可以访问Clang’s Blog:https://www.clang.asia


http://www.niftyadmin.cn/n/2521474.html

相关文章

flex 带打印预览功能的PrintJob

前几天看到论坛上有人需要flex中的打印预览功能&#xff0c;但是没有合适的方法来实现。经过我几天的努力&#xff0c;终于实现了flex的打印预览。把它做成了一个库文件&#xff0c;SuperPrintJob.swc。使用时只需要把SuperPrintJob类加入mxml或者在as代码中创建一个实例&#…

Spring中@Resource和@Autowire注解的区别

文章目录一、Resource和Autowire注解的区别二、详细说明什么是同类型的Bean总结一、Resource和Autowire注解的区别 Resource和Autowired都是用来进行依赖注入的注解&#xff0c;但是它们有一些不同之处。 Autowired是Spring框架中的注解&#xff0c;它可以用来标注字段、构造…

使用Collections.sort方法来对自定义对象进行排序

文章目录一、基本使用方法二、利用compare来实现一、基本使用方法 Collections.sort方法可以用来对自定义对象进行排序。要实现这一点&#xff0c;需要在调用该方法时传入一个比较器&#xff0c;该比较器用于指定如何比较对象中的值。 举个例子&#xff0c;假设有一个自定义对…

CentOS7一键安装python3

文章目录一、更新OpenSSL二、安装Python一、更新OpenSSL 1、安装依赖&#xff0c;下载安装包 yum install -y gcc libffi-devel zlib* openssl-devel libffi-devel zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-devel tk-devel gcc make perl …

ActionScript mxml flex 日期格式化 DateFormatter

跟Java很相似。都是使用一个格式化类来进行格式化&#xff1a; 第一步&#xff1a;var dateFormatter:DateFormatternew DateFormatter();//生成格式化对象 第二步&#xff1a;dateFormatter.formatString”YYYY-MM-DD JJ:NN:SS”;//设定格式 第三步&#xff1a;dateFormatt…

Java编程:Beanutils-No origin bean specified问题分析

Beanutils.copyProperties 异常一&#xff1a; No origin bean specified Beanutils.copyProperties 异常二&#xff1a; No destination bean specifiedBeanutils.copyProperties的源码:public void copyProperties(Object dest, Object orig) throws IllegalAccessException,…

开发中遇到的flex安全沙箱的问题

开发中遇到了安全沙箱的问题&#xff0c;一下有几种解决方案&#xff1a; 1. 播放器在 8.0 以上可以使用通配符 &ldquo;*&rdquo; 来允许所有域&#xff1a; System.security.allowDomain("*"); 如果要允许多个域&#xff0c;可以用逗号隔开&#xff1a; Syst…

C# []、Array、List、ArrayList 区别

[] 是针对特定类型、固定长度的。 Array 是针对任意类型、固定长度的。 List 是针对特定类型、任意长度的。 ArrayList 是针对任意类型、任意长度的。