为Nginx安装ngx_lua_waf以及配置动态封禁IP脚本
背景故事
最近经常有一些深圳南山的IP来爬站,咱也不知道是为毛,咱就一个个人博客而已,有啥好爬的呢。
经常爬的是CPU直接拉满,访问都访问不到了。
干脆搞一个脚本动态封禁算了。
安装ngx_lua_waf
这个算是比较常用的,也很好安装,之前没有写过笔记,干脆也罗列在这里算了。
1 2 3 4 5 |
cd /usr/local/nginx/lib git clone https://github.com/loveshell/ngx_lua_waf.git mv ngx_lua_waf/ /usr/local/nginx/conf/ cd /usr/local/nginx/conf mv ngx_lua_waf/ waf/ |
修改Nginx配置文件,在http段内添加:
1 2 3 4 |
lua_package_path /usr/local/nginx/conf/waf/?.lua; lua_shared_dict limit 10m; init_by_lua_file /usr/local/nginx/conf/waf/init.lua; access_by_lua_file /usr/local/nginx/conf/waf/waf.lua; |
如果已指定lua_package_path,可用双引号括起来之后追加,形式如下:
1 |
lua_package_path "/usr/local/nginx/lib/lua/?.lua;;/usr/local/nginx/conf/waf/?.lua"; |
修改ngx_lua_waf配置,日志目录需要Nginx的工作进程可以访问,所以要设置一下所有者。
1 2 3 |
mkdir /home/wwwlogs/hack chown www:www /home/wwwlogs/hack vim /usr/local/nginx/conf/waf/config.lua |
配置内需要修改的地方不多,就把规则目录的地址和日志目录的地址改一下就好了。
1 2 |
RulePath = "/usr/local/nginx/conf/waf/wafconf/" logdir = "/home/wwwlogs/hack/" |
可以访问如下地址来测试:
1 |
你的域名或IP/test.php?id=../etc/passwd |
出现如下图所示就是安装成功。
该样式可以在ngx_lua_waf
的配置文件config.lua
中修改。
动态封禁脚本
前置需要
需要Nginx安装Lua模块,并安装好lua-resty-redis
,被封禁IP是存储在Redis数据库内的。
为Nginx添加Lua模块以及安装lua-resty-redis
,可以参考上一篇文章。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
--redis服务器地址 local redis_service = "127.0.0.1" --redis服务器端口 local redis_port = tonumber(6379) --redis数据库 local redis_db = tonumber(1) --访问限制次数 local black_count = tonumber(50) --访问限制检测的时间,配合上面一条,也就是1秒内50次连接就会被封禁 local black_rule_unit_time = tonumber(1) --封禁时间 local cache_ttl = tonumber(86400) --从Nginx获取访问的IP地址 local remote_ip = ngx.var.remote_addr function ip_count(redis, status_key, count_key) local key = status_key local key_connect_count = count_key --从redis获取key local key_status = redis:get(key) --获取key的访问计数 local count = redis:get(key_connect_count) if key_status ~= ngx.null then --判断key的状态 if (key_status == "Connect" and count ~= ngx.null and tonumber(count) <= black_count) then --自增 count = redis:incr(key_connect_count) ngx.log(ngx.ERR, "count:", count) if count ~= ngx.null then if (tonumber(count) > black_count) then redis:del(key_connect_count) redis:set(key,"Black") --设置失效时间,如果是永久封禁,就将下面这一行注释或删除 redis:expire(key, cache_ttl) else redis:expire(key_connect_count, black_rule_unit_time) end end else ngx.log(ngx.ERR, "blocked ip") return ngx.exit(ngx.HTTP_FORBIDDEN) end else local count = redis:get(key) if count == ngx.null then redis:del(key_connect_count) end redis:set(key, "Connect") redis:set(key_connect_count, 1) redis:expire(key, black_rule_unit_time) redis:expire(key_connect_count, black_rule_unit_time) end end --redis连接超时时间 local redis_connect_timeout = 60 local redis = require "resty.redis" local red = redis:new() --key头 local auto_blacklist_key = "bk" red:set_timeout(redis_connect_timeout) local RedisConnectOk, RedisConnectErr = red:connect(redis_service, redis_port) red:select(redis_db) local key = auto_blacklist_key..":"..remote_ip local key_connect_count = auto_blacklist_key..":key_connect_count:"..remote_ip ip_count(red, key, key_connect_count) |
根据需求来修改访问限制次数即可。
由于IP是存储在Redis数据库内的,也可以通过其他支持脚本的检测平台或者自己写一个Python/Lua脚本来分析访问日志,将特定IP写入数据库即可完成封禁。
可扩展空间还是挺大的。
实装
假设脚本文件存储为/usr/local/nginx/lua/ipblock.lua
下,修改Nginx的配置文件,在http段中添加:
1 |
access_by_lua_file /usr/local/nginx/lua/ipblock.lua |
如果你有部署其他Lua脚本,那么就要自己想办法把动态封禁脚本整合进去,因为access_by_lua_file
指令是不允许多个同时存在的。
补充
对于连User-Agent都懒得换的爬虫来说,直接修改Nginx的配置,将指定User-Agent的访问都403了就好了。
配置如下:
1 2 3 4 5 6 7 8 9 |
#forbidden Scrapy if ($http_user_agent ~* (Scrapy|Curl|HttpClient)) { return 403; } #forbidden UA if ($http_user_agent ~ "Bytespider|FeedDemon|JikeSpider|Indy Library|Alexa Toolbar|AskTbFXTV|AhrefsBot|CrawlDaddy|CoolpadWebkit|Java|Feedly|UniversalFeedParser|ApacheBench|Microsoft URL Control|Swiftbot|ZmEu|oBot|jaunty|Python-urllib|python-requests|lightDeckReports Bot|YYSpider|DigExt|HttpClient|MJ12bot|heritrix|EasouSpider|SemrushBot|Ezooms|^$" ) { return 403; } |
后记
经过一段时间的运行,虽然偶尔还是会有CPU占用100%的情况,但监测平台上看已经只是1分钟这种很短时间的了。
Nginx+Lua这种模式,对于配置不太高的VPS来说还是很好用,轻量化。