2026/1/11 15:57:06
网站建设
项目流程
公司网站怎么管理,做logo图标的网站,手机客户端app下载安装,长治网站设计一、概述
在高并发场景下#xff0c;API接口防护是保证系统稳定性的关键环节。传统的Nginx限制模块#xff08;如ngx_http_limit_conn_module和ngx_http_limit_req_module#xff09;虽然功能强大#xff0c;但灵活性有限。本文将介绍如何结合Nginx、Lua和Redis实现更精细…一、概述在高并发场景下API接口防护是保证系统稳定性的关键环节。传统的Nginx限制模块如ngx_http_limit_conn_module和ngx_http_limit_req_module虽然功能强大但灵活性有限。本文将介绍如何结合Nginx、Lua和Redis实现更精细化的请求限制方案。核心需求对/myapi/**路径的请求进行验证只允许POST方法访问基于黑名单机制过滤非法请求阻止不符合规则的请求到达后端服务器二、技术架构组件选型Nginx: 高性能Web服务器OpenResty: 集成了Nginx和LuaJIT的Web平台Redis: 内存数据库存储黑名单数据Lua: 轻量级脚本语言实现业务逻辑架构优势高性能: Nginx的事件驱动模型保证高并发处理能力灵活性: Lua脚本实现业务逻辑无需修改Nginx源码实时性: Redis内存操作黑名单即时生效可扩展: 可轻松添加更多限制规则三、环境部署OpenResty安装# 安装依赖yuminstall-y gcc gcc-c readline-devel pcre-devel openssl-devel tcl perl# 下载OpenRestywgethttps://openresty.org/download/openresty-1.19.9.1.tar.gztarxzvf openresty-1.19.9.1.tar.gzcdopenresty-1.19.9.1/# 配置编译./configure --with-http_stub_status_module\--with-http_realip_module\--with-http_v2_module\--with-stream\--with-stream_realip_module\gmake gmakeinstall# 设置环境变量echoexport PATH/usr/local/openresty/bin:$PATH~/.bashrcsource~/.bashrcRedis安装配置# 安装Redisyuminstall-y redis# 配置Redisvim/etc/redis.conf# 修改以下配置# bind 127.0.0.1# requirepass yourpassword # 可选设置密码# maxmemory 256mb# maxmemory-policy allkeys-lru# 启动Redissystemctl start redis systemctlenableredis四、实现方案1. Lua限制脚本创建/usr/local/lua_test/my_access_limit.lua-- 请求限制核心逻辑localredisrequireresty.redislocalredredis:new()-- 设置Redis连接参数red:set_timeouts(1000,1000,1000)-- 连接/发送/接收超时(毫秒)-- 获取客户端真实IPlocalfunctionget_client_ip()localheadersngx.req.get_headers()localipheaders[X-Real-IP]orheaders[x_forwarded_for]orngx.var.remote_addr-- 处理多层代理的情况ifipandstring.find(ip,,)thenlocalips{}forvinstring.gmatch(ip,[^,%s])dotable.insert(ips,v)endipips[1]-- 取第一个IPendreturnipend-- 主处理函数localfunctionprocess_request()-- 只处理/myapi路径下的请求ifnotngx.re.match(ngx.var.uri,^/myapi/)thenreturnend-- 验证请求方法localmethodngx.var.request_methodifmethod~POSTthenngx.log(ngx.WARN,非POST请求被拒绝: ,ngx.var.uri)returnngx.exit(ngx.HTTP_FORBIDDEN)end-- 读取请求体ngx.req.read_body()localargsngx.req.get_post_args()-- 连接Redislocalok,errred:connect(127.0.0.1,6379)ifnotokthenngx.log(ngx.ERR,连接Redis失败: ,err)return-- 连接失败时放行请求避免单点故障end-- 可选Redis认证-- red:auth(yourpassword)-- 获取客户端IPlocalclient_ipget_client_ip()-- 检查黑名单localis_blacklistedfalselocalreasons{}-- 检查IP黑名单localres,errred:sismember(black:ip,client_ip)ifres1thenis_blacklistedtruetable.insert(reasons,IP在黑名单中)end-- 检查IMSI黑名单ifargs.imsithenres,errred:sismember(black:imsi,args.imsi)ifres1thenis_blacklistedtruetable.insert(reasons,IMSI在黑名单中)endend-- 检查电话号码黑名单ifargs.telthenres,errred:sismember(black:tel,args.tel)ifres1thenis_blacklistedtruetable.insert(reasons,电话在黑名单中)endend-- 检查设备ID黑名单ifargs.device_idthenres,errred:sismember(black:device,args.device_id)ifres1thenis_blacklistedtruetable.insert(reasons,设备ID在黑名单中)endend-- 将连接放回连接池localok,errred:set_keepalive(10000,100)ifnotokthenngx.log(ngx.ERR,设置Redis连接池失败: ,err)end-- 处理黑名单请求ifis_blacklistedthenngx.log(ngx.WARN,黑名单请求被阻止: ,IP,client_ip,, URI,ngx.var.uri,, 原因: ,table.concat(reasons,, ))-- 可选记录详细日志ngx.var.blacklist_reasontable.concat(reasons,, )-- 返回403禁止访问returnngx.exit(ngx.HTTP_FORBIDDEN)endend-- 执行主处理函数localok,errpcall(process_request)ifnotokthenngx.log(ngx.ERR,Lua脚本执行错误: ,err)-- 发生错误时放行请求避免阻断正常流量end2. Nginx配置创建/usr/local/openresty/nginx/conf/nginx.confworker_processes auto; error_log logs/error.log info; events { worker_connections 10240; use epoll; } http { include mime.types; default_type application/octet-stream; # 日志格式添加黑名单原因字段 log_format main $remote_addr - $remote_user [$time_local] $request $status $body_bytes_sent $http_referer $http_user_agent $http_x_forwarded_for $blacklist_reason; access_log logs/access.log main; # 设置Lua包路径 lua_package_path /usr/local/openresty/lualib/?.lua;;; lua_package_cpath /usr/local/openresty/lualib/?.so;;; # 共享内存可用于更高级的限流 lua_shared_dict my_limit_req_store 10m; lua_shared_dict my_limit_conn_store 10m; # 初始化阶段执行 init_by_lua_block { require resty.core } # 初始化worker时执行 init_worker_by_lua_block { -- 可在此处进行定时任务如清理过期黑名单 } upstream backend { server 127.0.0.1:8080; keepalive 100; } server { listen 80; server_name www.mysite.com; # 响应头添加安全相关信息 add_header X-Frame-Options SAMEORIGIN; add_header X-Content-Type-Options nosniff; add_header X-XSS-Protection 1; modeblock; # 全局黑名单检查 access_by_lua_file /usr/local/lua_test/my_access_limit.lua; # 默认路由 location / { root html; index index.html index.htm; } # API接口路由 location /myapi/ { # 请求体大小限制 client_max_body_size 1m; client_body_buffer_size 128k; # 连接后端服务器 proxy_pass http://backend; proxy_http_version 1.1; proxy_set_header Connection ; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; # 超时设置 proxy_connect_timeout 3s; proxy_send_timeout 10s; proxy_read_timeout 10s; # 缓冲设置 proxy_buffering on; proxy_buffer_size 4k; proxy_buffers 8 4k; } # 管理接口黑名单管理 location /admin/blacklist/ { # 限制内网访问 allow 192.168.1.0/24; allow 10.0.0.0/8; deny all; # 内容处理 default_type application/json; content_by_lua_file /usr/local/lua_test/blacklist_admin.lua; } # 状态监控接口 location /nginx_status { stub_status on; access_log off; allow 127.0.0.1; deny all; } } }3. 黑名单管理接口创建/usr/local/lua_test/blacklist_admin.lua-- 黑名单管理接口localcjsonrequirecjsonlocalredisrequireresty.redis-- 初始化响应ngx.header.content_typeapplication/json; charsetutf-8-- 连接Redislocalredredis:new()red:set_timeouts(1000,1000,1000)localok,errred:connect(127.0.0.1,6379)ifnotokthenngx.statusngx.HTTP_INTERNAL_SERVER_ERROR ngx.say(cjson.encode({code500,messageRedis连接失败: ..(error未知错误)}))returnend-- 认证-- red:auth(yourpassword)-- 根据请求方法处理localmethodngx.req.get_method()ifmethodGETthen-- 查询黑名单localtypengx.var.arg_typeoriplocalkeyblack:..typelocalitems,errred:smembers(key)ifitemsthenngx.say(cjson.encode({code0,messagesuccess,data{typetype,count#items,itemsitems}}))elsengx.say(cjson.encode({code500,message查询失败: ..(error未知错误)}))endelseifmethodPOSTthen-- 添加黑名单ngx.req.read_body()localargsngx.req.get_post_args()localtypeargs.typeoriplocalvalueargs.valueifnotvaluethenngx.statusngx.HTTP_BAD_REQUEST ngx.say(cjson.encode({code400,message参数value不能为空}))returnendlocalkeyblack:..typelocaladded,errred:sadd(key,value)ifaddedthenngx.say(cjson.encode({code0,message添加成功,data{typetype,valuevalue}}))elsengx.say(cjson.encode({code500,message添加失败: ..(error未知错误)}))endelseifmethodDELETEthen-- 移除黑名单localtypengx.var.arg_typeoriplocalvaluengx.var.arg_valueifnotvaluethenngx.statusngx.HTTP_BAD_REQUEST ngx.say(cjson.encode({code400,message参数value不能为空}))returnendlocalkeyblack:..typelocalremoved,errred:srem(key,value)ifremovedthenngx.say(cjson.encode({code0,message移除成功,data{typetype,valuevalue}}))elsengx.say(cjson.encode({code500,message移除失败: ..(error未知错误)}))endelsengx.statusngx.HTTP_METHOD_NOT_ALLOWED ngx.say(cjson.encode({code405,message不支持的请求方法}))end-- 关闭连接localok,errred:set_keepalive(10000,100)ifnotokthenngx.log(ngx.ERR,关闭Redis连接失败: ,err)end五、使用与管理1. 初始化黑名单# 添加IP到黑名单redis-cli sadd black:ip153.34.118.50redis-cli sadd black:ip192.168.1.100# 添加IMSI到黑名单redis-cli sadd black:imsi460123456789redis-cli sadd black:imsi460987654321# 添加电话到黑名单redis-cli sadd black:tel15888888888redis-cli sadd black:tel13966666666# 查看黑名单redis-cli smembers black:ip redis-cli smembers black:imsi redis-cli smembers black:tel2. 管理接口使用# 查询IP黑名单curlhttp://localhost/admin/blacklist/?typeip# 添加黑名单curl-X POST -dtypeipvalue10.0.0.1http://localhost/admin/blacklist/# 移除黑名单curl-X DELETEhttp://localhost/admin/blacklist/?typeipvalue10.0.0.13. 测试验证# 正常POST请求curl-X POST -dimsi460000000001tel13900000000\http://www.mysite.com/myapi/user/login# 黑名单IP请求被拒绝curl-X POST -dimsi460000000002tel13900000001\http://www.mysite.com/myapi/user/login\-HX-Real-IP: 153.34.118.50# GET请求被拒绝curlhttp://www.mysite.com/myapi/user/info六、高级功能扩展1. 频率限制增强版-- 基于IP的请求频率限制locallimit_reqrequireresty.limit.reqlocallimiter,errlimit_req.new(my_limit_req_store,10,1)-- 10 req/slocalkeyngx.var.binary_remote_addrlocaldelay,errlimiter:incoming(key,true)ifnotdelaytheniferrrejectedthenngx.exit(ngx.HTTP_SERVICE_UNAVAILABLE)endngx.log(ngx.ERR,限流失败: ,err)returnngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)endifdelay0thenngx.sleep(delay)end2. 动态黑名单自动封禁-- 自动检测并封禁恶意IPlocalfunctionauto_ban_ip(ip,reason)localredredis:new()localok,errred:connect(127.0.0.1,6379)ifokthen-- 封禁IPred:sadd(black:ip:auto,ip)-- 记录封禁原因和时间red:hset(black:ip:detail,ip,ngx.encode_args({reasonreason,timengx.localtime(),count1}))-- 设置过期时间24小时自动解封red:expire(black:ip:auto,86400)red:set_keepalive(10000,100)endend3. 白名单机制-- 在白名单中的请求直接放行localfunctionis_whitelist(ip)localredredis:new()localok,errred:connect(127.0.0.1,6379)ifokthenlocalis_whitered:sismember(white:ip,ip)red:set_keepalive(10000,100)returnis_white1endreturnfalseend七、性能优化建议1. Redis优化# 在Nginx中配置Redis连接池 lua_shared_dict redis_cluster_slot_locks 100k; lua_socket_connect_timeout 100ms; lua_socket_send_timeout 200ms; lua_socket_read_timeout 200ms;2. 缓存优化-- 使用共享字典缓存黑名单localfunctionis_ip_blacklisted(ip)localcachengx.shared.blacklist_cachelocalcachedcache:get(ip:..ip)ifcachedthenreturncached1end-- 缓存未命中查询Redislocalredredis:new()localok,errred:connect(127.0.0.1,6379)ifokthenlocalis_blackred:sismember(black:ip,ip)red:set_keepalive(10000,100)-- 缓存结果有效期5秒cache:set(ip:..ip,is_black1and1or0,5)returnis_black1endreturnfalseend3. 异步处理-- 使用ngx.timer.at进行异步处理localfunctionasync_log_blacklist(ip,reason)localok,errngx.timer.at(0,function()-- 异步记录日志到文件或数据库locallog_msgstring.format(%s - %s - %s\n,ngx.localtime(),ip,reason)localfile,errio.open(/var/log/nginx/blacklist.log,a)iffilethenfile:write(log_msg)file:close()endend)ifnotokthenngx.log(ngx.ERR,创建定时器失败: ,err)endend八、监控与告警1. 监控指标# 查看Nginx状态curlhttp://localhost/nginx_status# 查看黑名单统计redis-cli scard black:ip redis-cli scard black:imsi redis-cli scard black:tel# 查看拦截日志tail-f /usr/local/openresty/nginx/logs/access.log|grep黑名单2. 告警配置# 监控脚本示例#!/bin/bash# 检查黑名单数量BLACKLIST_COUNT$(redis-cli scard black:ip)if[$BLACKLIST_COUNT-gt1000];thenecho警告黑名单IP数量超过1000个|mail -s黑名单告警adminexample.comfi# 检查拦截频率INTERCEPT_COUNT$(grep-c黑名单/var/log/nginx/access.log2/dev/null||echo0)if[$INTERCEPT_COUNT-gt100];thenecho警告过去1小时拦截超过100次|mail -s拦截告警adminexample.comfi九、总结通过Nginx Lua Redis的组合我们实现了一个灵活、高效的请求限制系统。这个方案具有以下优势高性能利用Nginx的高并发处理能力和Redis的内存操作灵活性Lua脚本可以轻松实现各种复杂的业务逻辑实时性黑名单变更立即生效可扩展可以方便地添加新的限制规则和检查条件易维护配置和脚本分离便于管理和升级在实际生产环境中可以根据具体需求进一步扩展功能如添加更多维度的限制规则、实现更智能的恶意请求检测、集成监控告警系统等从而构建更加完善的安全防护体系。