首页 > 系统相关 >nginx+lua(OpenResty),实现访问限制

nginx+lua(OpenResty),实现访问限制

时间:2024-06-11 14:54:47浏览次数:29  
标签:count nginx request redis local lua limit OpenResty ngx

  因发现平台日志中不定时会有同一IP发送大量的正常请求的情况,因程序没做请求频率的限制,就打算使用nginx+lua(OpenResty)+redis来做控制,发现请求频率高的IP,直接封掉,禁止访问。

一、部署OpenResty

1、安装工具和依赖

 yum -y install  wget  vim  gcc pcre-devel  openssl-devel

 

2、从 https://github.com/openresty/openresty,下载OpenResty,这里使用openresty-1.25.3.1版本。

wget https://github.com/openresty/openresty/releases/download/v1.25.3.1/openresty-1.25.3.1.tar.gz

 

3、解压、配置、编译、安装

tar zxf  openresty-1.25.3.1.tar.gz
cd openresty-1.25.3.1
./configure --prefix=/data/openresty
gmake && gmake install

 

二、部署redis

  用redis来存储被封的IP,当然也可以考虑使用其他的方式,这里使用redis,假设redis密码为123456,传送阵:部署redis

 

三、编写lua脚本,启动redis

  1、在nginx配置文件中location模块里加入lua代码

    vim /data/openresty/nginx/conf/nginx.conf

http {

    .... 

    #创建一个共享内存区域来存储IP访问频率
    lua_shared_dict limit_req_store 10m;
    
    server {
        listen       80;
        
         ....
    
        location / {
            root   html;
            index  index.html index.htm;
            #添加lua脚本,access_by_lua_block指令
            access_by_lua_block {
                ngx.header.content_type = "text/plain; charset=utf-8"
                local request_limit = 50   -- 定义每个IP的请求频率限制变量
                local ttl = 1    -- 定义缓存过期时间变量,单位秒
                local redis_passwd = "123456" -- 定义redis密码
                local redis_host = "192.168.1.11" -- 定义redis服务器地址
                local redis_port = 6379  -- 定义redis端口信息
                local redis_set_key = "limit_ip"  -- 定义redis集合的key信息

                local redis = require "resty.redis"
                local red = redis:new()
                red:set_timeout(1000)
                local ok, err = red:connect(redis_host, redis_port) 
                if not ok then  
                    ngx.log(ngx.ERR,"连接redis出错: ", err)
                    return
                end
                ok , err = red:auth(redis_passwd)
                if not ok then
                    ngx.log(ngx.ERR,"redis授权失败:", err)
                    return
                end
                
                local cardinality ,err = red:scard(redis_set_key) 
                if cardinality == 0 then  
                    local my_limit = ngx.shared.my_limit_req_store
                    local client_ip = ngx.var.remote_addr
                    local request_count, _ = my_limit:get(client_ip)
                    if not request_count  then
                        request_count = 1
                    else 
                        request_count = request_count + 1
                    end
                    my_limit:set(client_ip,request_count,ttl)                
                    
                    if request_count > request_limit then  
                        red:sadd(redis_set_key,client_ip)
                        ngx.status = ngx.HTTP_TOO_MANY_REQUESTS
                        ngx.log(ngx.ERR,"该IP请求频率过高,已被禁止访问!",client_ip)
                        ngx.exit(ngx.HTTP_TOO_MANY_REQUESTS)
                    end
                else
                    local client_ip = ngx.var.remote_addr
                    local is_member, err = red:sismember(redis_set_key, client_ip)  
                    if err then
                        ngx.log(ngx.ERR,"检查IP是否存在于redis中出错: ", err)
                        return
                    end
                    if is_member == 0 then  
                        local my_limit = ngx.shared.my_limit_req_store
                        local client_ip = ngx.var.remote_addr
                        local request_count, _ = my_limit:get(client_ip)
                        if not request_count  then
                            request_count = 1
                        else
                            request_count = request_count + 1
                        end
                        my_limit:set(client_ip,request_count,ttl)

                        if request_count > request_limit then
                            red:sadd(redis_set_key,client_ip)
                            ngx.status = ngx.HTTP_TOO_MANY_REQUESTS
                            ngx.log(ngx.ERR,"该IP请求频率过高,已被禁止访问!",client_ip)
                            ngx.exit(ngx.HTTP_TOO_MANY_REQUESTS)
                        end
                    else 
                        ngx.status = ngx.HTTP_FORBIDDEN
                        ngx.log(ngx.ERR,"该IP已被禁止访问!",client_ip)
                        ngx.exit(ngx.HTTP_FORBIDDEN)
                    end   
                end  
                red:close()
            }
        }

        header_filter_by_lua_block {
            ngx.header.content_type = 'text/html; charset=utf-8'
        }

    }
}

  脚本说明:

    a、使用了redis的集合来存储封禁IP的信息

    b、access_by_lua_block 指令代码块可以放在http、server、location下来控制代码影响范围。

    c、request_limit参数的值和ttl的值来控制访问频率限制,以上代码是没秒钟50次请求。

    d、根据测试,使用一个静态的html页面(没有css、js等代码),请求1次,会执行2次access_by_lua_block指令,未找出具体原因,因此request_limit的值如果为20,ttl为1,那么在1秒内只能请求10次静态页面。

    e、该脚本对IP地址进行永久封禁(除非redis的数据丢失),如果想要实现限制时长功能,可以用其他方式存储,该方式解封就只能操作redis删除数据。

 

  2、启动nginx

/data/openresty/nginx/sbin/nginx

 

标签:count,nginx,request,redis,local,lua,limit,OpenResty,ngx
From: https://www.cnblogs.com/NanZhiHan/p/18242030

相关文章

  • Auto Arena of LLMs: Automating LLM Evaluations with Agent Peer-battles and Commi
    1.引言大语言模型(LLMs)发展迅速,亟需可靠的评估方法。静态数据集存在污染风险,人工评估平台耗时费力。提出自动、可靠、可信的评估框架:Auto-ArenaofLLMs(Auto-Arena)。2.相关工作自动评估方法:静态数据集和基于模型的评估。人工评估平台:ChatbotArena,存在耗时和语言......
  • 从零手写实现 nginx-17-nginx.conf 全局的默认配置
    前言大家好,我是老马。很高兴遇到你。我们为java开发者实现了java版本的nginxhttps://github.com/houbb/nginx4j如果你想知道servlet如何处理的,可以参考我的另一个项目:手写从零实现简易版tomcatminicat手写nginx系列如果你对nginx原理感兴趣,可以阅读:从零......
  • nginx中的限速
    nginx中的限速分为限流量(limit_rate)、限数量(limit_req)、限连接(limit_conn)配置Limit_rate限制的是某个请求的response速率。不同请求间的response速率不受影响。配置方法:https://github.com/zongzw-learn/learn-nginx/blob/main/limit/limit_rate.yamlLimit_req限制......
  • 从零手写实现 nginx-15-nginx.conf 解析处理转换为 POJO
    前言大家好,我是老马。很高兴遇到你。我们为java开发者实现了java版本的nginxhttps://github.com/houbb/nginx4j如果你想知道servlet如何处理的,可以参考我的另一个项目:手写从零实现简易版tomcatminicat手写nginx系列如果你对nginx原理感兴趣,可以阅读:从零......
  • 运维系列:nginx 重启报nginx: [error] invalid PID number ““ in “/run/nginx.pid“
    这nginx重启报nginx:[error]invalidPIDnumber““in“/run/nginx.pid“nginx重启报nginx:[error]invalidPIDnumber““in“/run/nginx.pid“为何出现这种原因?解决方式:nginx重启报nginx:[error]invalidPIDnumber““in“/run/nginx.pid“......
  • 在centos7.9下编译安装nginx1.16.1带fancyindex
    在centos7.9下编译安装nginx1.16.1带fancyindex文章目录前言一、安装环境centos7.9/nginx1.16.1/ngx-fancyindex-0.4.4二、需要达到的效果1.默认效果2.安装主题效果三、nginx编译安装1.安装依赖工具2.创建目录并下载Nginx及其模块3.运行编译与安装4.配置环境变......
  • Nginx Rewrite
    目录1.常用的Nginx正则表达式2.location3.rewrite1.常用的Nginx正则表达式^:匹配输入字符串的起始位置$:匹配输入字符串的结束位置*:匹配前面的字符零次或多次。如“ol*”能匹配“o”及“ol”、“oll”+:匹配前面的字符一次或多次。如“ol+”能匹配“ol”及“oll”、“olll......
  • 从零手写实现 nginx-13-nginx.conf 配置例子解释 + nginx 配置文件要如何解析?
    前言大家好,我是老马。很高兴遇到你。我们为java开发者实现了java版本的nginxhttps://github.com/houbb/nginx4j如果你想知道servlet如何处理的,可以参考我的另一个项目:手写从零实现简易版tomcatminicat手写nginx系列如果你对nginx原理感兴趣,可以阅读:从零......
  • Nginx图片下载不完整的处理过程
    Nginx图片下载不完整的处理过程背景昨天同事进行了nginx的迁移然后晚上发现图片展示不全.自己其实之前遇到过类似的问题但是因为熬夜比较久,脑子已经不转了.所以花了接近半小时才理清楚.感觉一些事情不记录一下,无法加深印象.问题现象客户的nginx从之前的CentOS迁移......
  • nginx快速分析日志并找出攻击IP
    第一步:分析NGINX日志分析日志主要目的是寻找那些异常活跃的IP地址,通过以下命令可以快速找出。 cataccess.log|awk'{print$1}'|sort|uniq-c|sort-rn|head-10命令说明:cataccess.log:将access.log文件的内容输出到标准输出。awk'{print$1}':awk是一个强大的文本......