Nacos实现IP动态黑白名单过滤

news2024/12/28 18:34:50

一些恶意用户(可能是黑客、爬虫、DDoS 攻击者)可能频繁请求服务器资源,导致资源占用过高。因此我们需要一定的手段实时阻止可疑或恶意的用户,减少攻击风险。
 

本次练习使用到的是Nacos配合布隆过滤器实现动态IP黑白名单过滤

文章目录

目录

文章目录

一、IP黑白名单是什么?

二、使用步骤

1.使用Nacos

1.通过Nacos添加配置

2.引入依赖

2.使用

1.定义一个获取IP的方法

2.创建黑名单过滤工具类

3.创建Nacos配置监听类

4.创建黑白名单过滤器

总结


一、IP黑白名单是什么?

一些恶意用户(可能是黑客、爬虫、DDoS 攻击者)可能频繁请求服务器资源,导致资源占用过高。因此我们需要一定的手段实时阻止可疑或恶意的用户,减少攻击风险。

通过 IP 封禁,可以有效拉黑攻击者,防止资源被滥用,保障合法用户的正常访问。

对于我们的需求,不让拉进黑名单的 IP 访问任何接口。

二、使用步骤

1.使用Nacos

首先就是下载Nacos

通过网盘分享的文件:nacos
链接: https://pan.baidu.com/s/12-9UA6hUSlEeyuKVfNPkJw?pwd=fr2z 提取码: fr2z 
--来自百度网盘超级会员v6的分享

拿到文件夹内容是

 打开bin目录

//运行命令行
startup.sh -m standalone

 

 看到这个界面就代表着Nacos运行成功了

1.通过Nacos添加配置

访问:http://127.0.0.1:8848/nacos ,默认用户名和密码都是 nacos

此时创建自己的配置

 

 之后选择发布

2.引入依赖

<dependency>
    <groupId>com.alibaba.boot</groupId>
    <artifactId>nacos-config-spring-boot-starter</artifactId>
    <version>0.2.12</version>
</dependency>


        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.8</version>
        </dependency>

 在application.yml中添加依赖

# 配置中心
nacos:
  config:
    server-addr: 127.0.0.1:8848  # nacos 地址
    bootstrap:
      enable: true  # 预加载
    data-id: 这里填写上面你在配置文件里面填写的Data ID # 控制台填写的 Data ID
    group: DEFAULT_GROUP # 控制台填写的 group
    type: yaml  # 选择的文件格式
    auto-refresh: true # 开启自动刷新

2.使用

1.定义一个获取IP的方法

package com.hhh.mianshiya.utils;

import java.net.InetAddress;
import javax.servlet.http.HttpServletRequest;

/**
 * 网络工具类
 *
 * @author <a href="https://github.com/liyupi">程序员鱼皮</a>
 * @from <a href="https://yupi.icu">编程导航知识星球</a>
 */
public class NetUtils {

    /**
     * 获取客户端 IP 地址
     *
     * @param request
     * @return
     */
    public static String getIpAddress(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
            if (ip.equals("127.0.0.1")) {
                // 根据网卡取本机配置的 IP
                InetAddress inet = null;
                try {
                    inet = InetAddress.getLocalHost();
                } catch (Exception e) {
                    e.printStackTrace();
                }
                if (inet != null) {
                    ip = inet.getHostAddress();
                }
            }
        }
        // 多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割
        if (ip != null && ip.length() > 15) {
            if (ip.indexOf(",") > 0) {
                ip = ip.substring(0, ip.indexOf(","));
            }
        }
        if (ip == null) {
            return "127.0.0.1";
        }
        return ip;
    }

}

2.创建黑名单过滤工具类

package com.hhh.mianshiya.blackfilter;

import cn.hutool.bloomfilter.BitMapBloomFilter;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.yaml.snakeyaml.Yaml;

import java.util.Collections;
import java.util.List;
import java.util.Map;

@Slf4j
public class BlackIpUtils {

    // 声明一个静态的、线程安全的布隆过滤器实例
    private static volatile BitMapBloomFilter bloomFilter;
    
    /**
     * 判断 IP 是否在黑名单中
     * 
     * @param ip 待检查的 IP 地址
     * @return 如果 IP 地址在黑名单中,则返回 true;否则返回 false
     */
    public static boolean isBlackIp(String ip) {
        // 防御性编程,防止 bloomFilter 未初始化时调用
        if (bloomFilter == null) {
            log.warn("Bloom filter is not initialized. Returning false for IP: {}", ip);
            return false;
        }
        return bloomFilter.contains(ip);
    }
    
    /**
     * 重建黑名单布隆过滤器
     * 
     * @param configInfo 包含黑名单配置信息的字符串
     */
    public static void rebuildBlackIp(String configInfo) {
        // 处理空或无效的配置信息
        if (StrUtil.isBlank(configInfo)) {
            log.warn("你没有传递配置文件的内容");
            configInfo = "{}";
        }
    
        try {
            // 解析 Yaml 文件
            Yaml yaml = new Yaml();
            Map<String, Object> map = yaml.loadAs(configInfo, Map.class);
    
            // 获取黑名单列表
            List<String> blackIpList = (List<String>) map.getOrDefault("blackIpList", Collections.emptyList());
    
            synchronized (BlackIpUtils.class) {
                // 构建布隆过滤器
                BitMapBloomFilter bitMapBloomFilter = new BitMapBloomFilter(
                        Math.max(blackIpList.size(), 100)); // 设置合理的默认容量
    
                // 填充黑名单 IP
                for (String ip : blackIpList) {
                    bitMapBloomFilter.add(ip);
                }
    
                // 替换静态布隆过滤器
                bloomFilter = bitMapBloomFilter;
    
                log.info("Bloom filter rebuilt successfully with {} IPs.", blackIpList.size());
            }
        } catch (Exception e) {
            log.error("Failed to rebuild Bloom filter. Config info: {}", configInfo, e);
            // 如果发生异常,使用一个默认空的布隆过滤器
            synchronized (BlackIpUtils.class) {
                bloomFilter = new BitMapBloomFilter(100);
            }
        }
    }
}

3.创建Nacos配置监听类

在 blackfilter 包中新增监听器代码,追求性能的话可以自定义线程池

package com.hhh.mianshiya.blackfilter;

import com.alibaba.nacos.api.annotation.NacosInjected;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.Listener;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.validation.constraints.NotNull;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;

// 使用slf4j日志框架记录日志信息
@Slf4j
// 标识该类为Spring框架的组件,自动注入到Spring容器中
@Component
public class NacosListener implements InitializingBean {

    // 注入Nacos配置服务
    @NacosInjected
    private ConfigService configService;

    // 从配置中获取Nacos数据ID
    @Value("${nacos.config.data-id}")
    private String dataId;

    // 从配置中获取Nacos分组信息
    @Value("${nacos.config.group}")
    private String group;

    // 实现InitializingBean接口,当所有属性设置完毕后调用此方法
    @Override
    public void afterPropertiesSet() throws Exception {
        // 记录日志:nacos监听器启动
        log.info("nacos 监听器启动");

        // 从Nacos中获取配置信息,并添加配置变更监听器
        String config = configService.getConfigAndSignListener(dataId, group, 3000L, new Listener() {
            // 创建线程工厂,用于生成线程池中的线程
            final ThreadFactory threadFactory = new ThreadFactory() {
                // 用于生成线程池编号
                private final AtomicInteger poolNumber = new AtomicInteger(1);

                // 创建并配置线程
                @Override
                public Thread newThread(@NotNull Runnable r) {
                    Thread thread = new Thread(r);
                    // 设置线程名称
                    thread.setName("refresh-ThreadPool" + poolNumber.getAndIncrement());
                    return thread;
                }
            };
            // 创建固定大小的线程池,用于异步处理配置变更事件
            final ExecutorService executorService = Executors.newFixedThreadPool(1, threadFactory);

            // 通过线程池异步处理黑名单变化的逻辑
            @Override
            public Executor getExecutor() {
                return executorService;
            }

            // 监听后续黑名单变化
            @Override
            public void receiveConfigInfo(String configInfo) {
                // 记录日志:监听到配置信息变化
                log.info("监听到配置信息变化:{}", configInfo);
                // 调用工具类方法,根据新的配置信息更新黑名单
                BlackIpUtils.rebuildBlackIp(configInfo);
            }
        });
        // 初始化黑名单
        BlackIpUtils.rebuildBlackIp(config);
    }
}

4.创建黑白名单过滤器

@WebFilter(urlPatterns = "/*", filterName = "blackIpFilter")
public class BlackIpFilter implements Filter {

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

        String ipAddress = NetUtils.getIpAddress((HttpServletRequest) servletRequest);
        if (BlackIpUtils.isBlackIp(ipAddress)) {
            servletResponse.setContentType("text/json;charset=UTF-8");
            servletResponse.getWriter().write("{\"errorCode\":\"-1\",\"errorMsg\":\"黑名单IP,禁止访问\"}");
            return;
        }
        filterChain.doFilter(servletRequest, servletResponse);
    }

}

此时添加上这个过滤器之后需要在主类上面添加注解

@ServletComponentScan

此时访问接口


总结

今天看了鱼皮的项目,第一次接触到了这种商业性质的思路,颇有感触,特写下博客记录

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

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

相关文章

如何在Word文件中设置水印以及如何禁止修改水印

在日常办公和学习中&#xff0c;我们经常需要在Word文档中设置水印&#xff0c;以保护文件的版权或标明文件的机密性。水印可以是文字形式&#xff0c;也可以是图片形式&#xff0c;能够灵活地适应不同的需求。但仅仅设置水印是不够的&#xff0c;有时我们还需要确保水印不被随…

测试工程师如何在面试中脱颖而出

目录 1.平时工作中是怎么去测的&#xff1f; 2.B/S架构和C/S架构区别 3.B/S架构的系统从哪些点去测&#xff1f; 4.你为什么能够做测试这一行&#xff1f;&#xff08;根据个人情况分析理解&#xff09; 5.你认为测试的目的是什么&#xff1f; 6.软件测试的流程&#xff…

jenkins的安装(War包安装)

‌Jenkins是一个开源的持续集成工具&#xff0c;基于Java开发&#xff0c;主要用于监控持续的软件版本发布和测试项目。‌ 它提供了一个开放易用的平台&#xff0c;使软件项目能够实现持续集成。Jenkins的功能包括持续的软件版本发布和测试项目&#xff0c;以及监控外部调用执行…

无线感知会议系列【15】DPSense-2

接&#xff1a; 无线感知会议系列【15】DPSense-1 目录&#xff1a; 实验 讨论 结论 附录 一 实验 在本节中&#xff0c;我们通过全面的实验验证了所提出的DPSense系统的有效性。首先&#xff0c;我们将我们的方法与三种最先进的技术进行了比较。然后&#xff0c…

AI编程入门指南002:API、数据库和应用部署

进阶概念教程&#xff1a;API、数据库和应用部署 在学习了编程的基础概念后&#xff0c;我们将进入更高级的内容。本文将详细介绍API、数据库和应用部署三个进阶概念&#xff0c;并通过丰富的示例和形象的说明帮助你更好地理解这些内容。 1. API&#xff08;应用程序接口&#…

Docker3:docker基础1

欢迎来到“雪碧聊技术”CSDN博客&#xff01; 在这里&#xff0c;您将踏入一个专注于Java开发技术的知识殿堂。无论您是Java编程的初学者&#xff0c;还是具有一定经验的开发者&#xff0c;相信我的博客都能为您提供宝贵的学习资源和实用技巧。作为您的技术向导&#xff0c;我将…

《Django 5 By Example》阅读笔记:p645-p650

《Django 5 By Example》学习第8天&#xff0c;p645-p650总结&#xff0c;总计6页。 一、技术总结 1.django-rest-framework (1)serializer p648, Serializer: Provides serialization for normal Python class instances。Serializer又细分为Serializer, ModelSerializer,…

【机器学习】回归模型(线性回归+逻辑回归)原理详解

线性回归 Linear Regression 1 概述 线性回归类似高中的线性规划题目。线性回归要做的是就是找到一个数学公式能相对较完美地把所有自变量组合&#xff08;加减乘除&#xff09;起来&#xff0c;得到的结果和目标接近。 线性回归分为一元线性回归和多元线性回归。 2 一元线…

【大模型推理】vLLM 源码学习

强烈推荐 https://zhuanlan.zhihu.com/p/680153425 sequnceGroup 存储了相同的prompt对应的不同的sequence, 所以用字典存储 同一个Sequence可能占据多个逻辑Block&#xff0c; 所以在Sequence 中用列表存储 同一个block 要维护tokens_id 列表, 需要添加操作。 还需要判断blo…

FIFO和LRU算法实现操作系统中主存管理

FIFO&#xff0c;用数组实现 1和2都是使用nextReplace实现新页面位置的更新 1、不精确时间&#xff1a;用ctime输出运行时间都是0.00秒 #include <iostream> #include <iomanip> #include<ctime>//用于计算时间 using namespace std;// 页访问顺序 int pa…

【Ubuntu24.04】VirtualBox安装ubuntu-live-server24.04

目录 0 背景1 下载镜像2 安装虚拟机3 安装UbuntuServer24.044 配置基本环境5 总结0 背景 有了远程连接工具之后,似乎作为服务器的Ubuntu24.04桌面版有点备受冷落了,桌面版的Ubuntu24.04的优势是图形化桌面,是作为一个日常工作的系统来用的,就像Windows,如果要作为服务器来…

《SpringBoot、Vue 组装exe与套壳保姆级教学》

&#x1f4e2; 大家好&#xff0c;我是 【战神刘玉栋】&#xff0c;有10多年的研发经验&#xff0c;致力于前后端技术栈的知识沉淀和传播。 &#x1f497; &#x1f33b; CSDN入驻不久&#xff0c;希望大家多多支持&#xff0c;后续会继续提升文章质量&#xff0c;绝不滥竽充数…

Flowable第一篇、快速上手(Flowable安装、配置、集成)

目录 Flowable 概述Flowable的安装与配置 2.1. FlowableUI安装 2.2. Flowable BPMN插件下载 2.3 集成Spring Boot流程审核操作 3.3 简单流程部署 3.4 启动流程实例 3.5 流程审批 一、Flowable 概述 Flowable是一个轻量级、高效可扩展的工作流和业务流程管理&#xff08;BPM&…

Docker搭建有UI的私有镜像仓库

Docker搭建有UI的私有镜像仓库 一、使用这个docker-compose.yml文件&#xff1a; version: 3services:registry-ui:image: joxit/docker-registry-ui:2.5.7-debianrestart: alwaysports:- 81:80environment:- SINGLE_REGISTRYtrue- REGISTRY_TITLEAtt Docker Registry UI- DE…

容器安全检测和渗透测试工具

《Java代码审计》http://mp.weixin.qq.com/s?__bizMzkwNjY1Mzc0Nw&mid2247484219&idx1&sn73564e316a4c9794019f15dd6b3ba9f6&chksmc0e47a67f793f371e9f6a4fbc06e7929cb1480b7320fae34c32563307df3a28aca49d1a4addd&scene21#wechat_redirect Docker-bench-…

Day10_CSS过度动画

Day10_CSS过度动画 背景 : PC和APP项目我们已经开发完毕, 但是再真正开发的时候有些有些简易的动态效果我们可以使用CSS完成 ; 本节课我们来使用CSS完成基础的动画效果 今日学习目标 CSS3过度CSS3平面动态效果CSS3动画效果案例 1. CSS3过渡 ​ 含义 :过渡指的是元素从一种…

iOS应用网络安全之HTTPS

移动互联网开发中iOS应用的网络安全问题往往被大部分开发者忽略, iOS9和OS X 10.11开始Apple也默认提高了安全配置和要求. 本文以iOS平台App开发中对后台数据接口的安全通信进行解析和加固方法的分析. 1. HTTPS/SSL的基本原理 安全套接字层 (Secure Socket Layer, SSL) 是用来…

excel版数独游戏(已完成)

前段时间一个朋友帮那小孩解数独游戏&#xff0c;让我帮解&#xff0c;我看他用电子表格做&#xff0c;只能显示&#xff0c;不能显示重复&#xff0c;也没有协助解题功能&#xff0c;于是我说帮你做个电子表格版的“解题助手”吧&#xff0c;不能直接解题&#xff0c;但该有的…

金融数据中心容灾“大咖说” | 美创科技赋能“灾备一体化”建设

中国人民银行发布的《金融数据中心容灾建设指引》&#xff08;JR/T 0264—2024&#xff09;已于2024年7月29日正式实施。这一金融行业标准对金融数据中心容灾建设中的“组织保障、需求分析、体系规划、建设要求、运维管理”进行了规范和指导。面对不断增加的各类网络、业务、应…

Qt:信号槽

一. 信号槽概念 信号槽 是 Qt 框架中一种用于对象间通信的机制 。它通过让一个对象发出信号&#xff0c;另一个对象连接到这个信号的槽上来实现通信。信号槽机制是 Qt 的核心特性之一&#xff0c;提供了一种灵活且类型安全的方式来处理事件和数据传递。 1. 信号的本质 QT中&a…