Nginx实现动态拦截非法访问ip的方法

 更新时间:2025年02月27日 11:00:28   作者:风雨_83  
最近在访问时不时会被暴力刷量,爬虫和恶意攻击导致数据库,服务等瘫痪,所以本文介绍了在Nginx上实现一个动态拦截IP的方法,具体是当某个IP在1分钟内访问超过60次时,将其加入Redis并拦截,拦截时间默认1天,需要的朋友可以参考下

 背景:访问时不时会被暴力刷量,爬虫和恶意攻击导致数据库,服务等瘫痪

需求:在Nginx上实现一个动态拦截IP的方法,具体是当某个IP在1分钟内访问超过60次时,将其加入Redis并拦截,拦截时间默认1天。

技术选型:使用Nginx+Lua+Redis的方法。这种方案通过Lua脚本在Nginx处理请求时检查Redis中的黑名单,同时统计访问频率,超过阈值就封禁。这应该符合用户的需求。

需要结合Lua脚本和Redis的计数功能。安装OpenResty,配置Nginx的Lua模块,编写Lua脚本统计访问次数,使用Redis存储和过期键,以及设置拦截逻辑。连接池的使用,避免频繁连接Redis影响性能。

一、环境准备

  • 安装OpenResty

OpenResty集成了Nginx和Lua模块,支持直接运行Lua脚本:

# Ubuntu/Debian
sudo apt-get install openresty
# CentOS
yum install openresty
  • 安装Redis服务
sudo apt-get install redis-server  # Debian系
sudo yum install redis             # RedHat系

二、Nginx配置

  • 主配置文件(nginx.conf)http块中添加共享内存和Lua脚本路径:

http {
    lua_package_path "/usr/local/openresty/lualib/?.lua;;";
    lua_shared_dict ip_limit 10m;  # 共享内存区

    server {
        listen 80;
        server_name _;

        location / {
            access_by_lua_file /usr/local/lua/ip_block.lua;  # 核心拦截脚本
            root /var/www/html;
        }
    }
}

三、Lua脚本实现动态拦截

  • 脚本路径创建Lua脚本:/usr/local/lua/ip_block.lua

  • 脚本内容

local redis = require "resty.redis"
local red = redis:new()

-- Redis连接参数
local redis_host = "127.0.0.1"
local redis_port = 6379
local redis_timeout = 1000  -- 毫秒
local redis_auth = nil       -- 无密码留空

-- 拦截参数
local block_time = 86400     -- 封禁时间(1天)
local time_window = 60       -- 统计窗口(1分钟)
local max_requests = 60     -- 最大请求数

-- 获取客户端IP
local function get_client_ip()
    local headers = ngx.req.get_headers()
    return headers["X-Real-IP"] or headers["x_forwarded_for"] or ngx.var.remote_addr
end

-- 连接Redis
local function connect_redis()
    red:set_timeout(redis_timeout)
    local ok, err = red:connect(redis_host, redis_port)
    if not ok then
        ngx.log(ngx.ERR, "Redis连接失败: ", err)
        return nil
    end
    if redis_auth then
        local ok, err = red:auth(redis_auth)
        if not ok then ngx.log(ngx.ERR, "Redis认证失败: ", err) end
    end
    return ok
end

-- 主逻辑
local client_ip = get_client_ip()
local counter_key = "limit:count:" .. client_ip
local block_key = "limit:block:" .. client_ip

-- 检查是否已封禁
local is_blocked, err = red:get(block_key)
if tonumber(is_blocked) == 1 then
    ngx.exit(ngx.HTTP_FORBIDDEN)  -- 直接返回403
end

-- 统计请求次数
connect_redis()
local current_count = red:incr(counter_key)
if current_count == 1 then
    red:expire(counter_key, time_window)  -- 首次设置过期时间
end

-- 触发封禁条件
if current_count > max_requests then
    red:setex(block_key, block_time, 1)   -- 封禁并设置1天过期
    red:del(counter_key)                  -- 删除计数器
    ngx.exit(ngx.HTTP_FORBIDDEN)
end

-- 释放Redis连接
red:set_keepalive(10000, 100)

四、性能优化

  • Redis连接池通过set_keepalive复用连接,避免频繁建立TCP连接
  • 共享内存缓存使用lua_shared_dict缓存高频访问IP,减少Redis查询压力
  • 异步日志记录封禁操作异步写入日志文件,避免阻塞请求处理:

ngx.timer.at(0, function()
    local log_msg = string.format("%s - IP %s blocked at %s", 
        ngx.var.host, client_ip, ngx.localtime())
    local log_file = io.open("/var/log/nginx/blocked_ips.log", "a")
    log_file:write(log_msg, "\n")
    log_file:close()
end)

五、验证与测试

  • 手动触发封禁
# 模拟高频请求
ab -n 100 -c 10 http://your-domain.com/
# 检查Redis
redis-cli keys "limit:block:*"
  • 自动解封验证

等待24小时后检查封禁IP是否自动删除:

redis-cli ttl "limit:block:1.2.3.4"  # 返回剩余秒数

六、扩展方案

  • 分布式封禁
    在多台Nginx服务器间共享Redis黑名单,实现集群级拦截
  • 可视化监控
    通过Grafana+Prometheus展示实时拦截数据:

# 采集Redis指标
prometheus-redis-exporter --redis.address=localhost:6379
  • 动态调整阈值
    通过Redis Hash存储不同路径的拦截规则:
local rule_key = "limit:rule:" .. ngx.var.uri
local custom_rule = red:hget(rule_key, "max_requests")

引用说明

  • 核心拦截逻辑参考了Nginx+Lua+Redis的经典架构设计
  • Redis键过期机制确保自动解封
  • 性能优化方案借鉴了OpenResty最佳实践

以上就是Nginx实现动态拦截非法访问ip的方法的详细内容,更多关于Nginx动态拦截IP的资料请关注脚本之家其它相关文章!

相关文章

  • Nginx与Lua灰度发布的实现

    Nginx与Lua灰度发布的实现

    这篇文章主要介绍了Nginx与Lua灰度发布的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-03-03
  • Nginx的流式响应配置实现小结

    Nginx的流式响应配置实现小结

    nginx是一款自由的、开源的、高性能的HTTP服务器和反向代理服务器,本文主要介绍了Nginx的流式响应配置实现小结,具有一定的参考价值,感兴趣的可以了解一下
    2024-04-04
  • 1分钟搞定Nginx版本的平滑升级与回滚的方法

    1分钟搞定Nginx版本的平滑升级与回滚的方法

    这篇文章主要介绍了1分钟搞定Nginx版本的平滑升级与回滚的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-10-10
  • CentOS 7.0下nginx实现每天定时分割日志

    CentOS 7.0下nginx实现每天定时分割日志

    大家都知道Nginx产生的日志都是存在一个文件,随着网站运行时间越长,日志文件的大小也在不断增长,所以这个时候就需要实现定时分割,这篇文章主要介绍了在CentOS 7.0下nginx实现每天定时分割日志的相关资料,需要的朋友可以参考下。
    2017-04-04
  • 通过nginx实现访问服务器指定目录下图片资源

    通过nginx实现访问服务器指定目录下图片资源

    这篇文章为大家详细主要介绍了如何通过nginx实现访问服务器指定目录下图片资源,文中通过图文进行了详细的讲解,有需要的小伙伴可以了解下
    2023-10-10
  • 使用nginx解决前端js下载跨域问题

    使用nginx解决前端js下载跨域问题

    订单系统增加附件预览,下载的功能,但是这个附件是客户推单时推送过来的,文件连接是类似oss连接,但是是客户的域名,所以导致跨域问题,本文小编将给大家介绍如何用nginx解决前端js下载跨域问题,需要的朋友可以参考下
    2023-10-10
  • 强大的Nginx配置生成器详解

    强大的Nginx配置生成器详解

    Nginx Config 是一款可以一键生成 Nginx 配置的神器,相当给力,这篇文章主要介绍了强大的Nginx配置生成器,需要的朋友可以参考下
    2022-11-11
  • nginx报错connect() failed(111: Connection refused)while connecting to upstream解决方法

    nginx报错connect() failed(111: Connection refus

    本文主要介绍了nginx报错connect() failed(111: Connection refused)while connecting to upstream解决方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-06-06
  • nginx反向代理时如何保持长连接

    nginx反向代理时如何保持长连接

    如果我们使用了nginx去作为反向代理或者负载均衡,从客户端过来的长连接请求就会被转换成短连接发送给服务器端。为了支持长连接,我们需要在nginx服务器上做一些配置。
    2020-10-10
  • 神器!最佳 Nginx 日志分析工具 GoAccess

    神器!最佳 Nginx 日志分析工具 GoAccess

    非常小又精悍的 Nginx 日志分析工具 GoAccess,今天在 CentOS VPS 上安装测试了一番,就2个字,神器!
    2014-02-02

最新评论