自己搭建的网站刚上线,短信接口就被一直攻击,并且攻击者不停变换IP,导致阿里云短信平台上的短信被恶意刷取了几千条,加上最近工作比较忙,就直接在OpenResty上对短信接口做了一些限制,采用OpenResty+Lua的方案成功动态封禁了频繁刷短信接口的IP。
一、临时解决方案
由于事情比较紧急,所以,当发现这个问题时,就先采用快速的临时方案解决。
(1)查看Nginx日志发现被攻击的IP 和接口
发现攻击者一直在用POST请求 /fhtowers/user/getVerificationCode这个接口
图片
(2)用awk和grep脚本过滤nginx日志,提取攻击短信接口的ip(一般这个接口是用来发注册验证码的,一分钟如果大于10次请求的话就不是正常的访问请求了,大家根据自己的实际情况更改脚本)并放到一个txt文件中去,然后重启nginx
(3)设置Nginx去读取用脚本过滤出来的blocksip.txt(注意一下,我这里的Nginx是用的openresty,自带识别lua语法的,下面会有讲openresty的用法)
(4)把过滤脚本放进crontab任务里,一分钟执行一次
(5)查看一下效果,发现攻击者的请求都被返回403并拒绝了
图片
二、OpenResty+Lua方案
临时方案有效果后,再将其调整成使用OpenResty+Lua脚本的方案,来一张草图。
图片
接下来,就是基于OpenResty和Redis实现自动封禁访问频率过高的IP。
2.1 安装OpenResty
安装使用 OpenResty,这是一个集成了各种 Lua 模块的 Nginx 服务器,是一个以Nginx为核心同时包含很多第三方模块的Web应用服务器,使用Nginx的同时又能使用lua等模块实现复杂的控制。
(1)安装编译工具、依赖库
(2)下载openresty-1.13.6.1.tar.gz 源码包,并解压;下载ngx_cache_purge模块,该模块用于清理nginx缓存;下载nginx_upstream_check_module模块,该模块用于ustream健康检查。
(3)配置需安装的模块
(4)创建一个软链接方便启动停止
(5)启动nginx
如果启动时候报错找不到PID的话就用以下命令解决(如果没有更改过目录的话,让它去读nginx的配置文件就好了)
图片
随后,打开浏览器访问页面。
图片
(6)在Nginx上测试一下能否使用Lua脚本
在server里面加一个
图片
加完后重新reload配置。
在浏览器里输入 ip地址/lua,出现下面的字就表示Nginx能够成功使用lua了
图片
2.2 安装Redis
(1)下载、解压、编译安装
(2)查看是否安装成功
(3)配置redis 创建dump file、进程pid、log目录
(4)修改配置文件
(5)设置启动方式
/etc/init.d/redis文件的内容如下。
增加执行权限,并启动Redis。
(6)查看redis是否启动
图片
2.3 Lua访问Redis
(1)连接redis,然后添加一些测试参数
(2)编写连接Redis的Lua脚本
(3)在nginx.conf配置文件中的server下添加以下location
随后重新reload配置。
(4)验证Lua访问Redis的正确性
在浏览器输入ip/lua_redis, 如果能看到下图的内容表示Lua可以访问Redis。
图片
准备工作已经完成,现在要实现OpenResty+Lua+Redis自动封禁并解封IP了。3.4
2.4 OpenResty+Lua实现
(1)添加访问控制的Lua脚本(只需要修改Lua脚本中连接Redis的IP和端口即可)
注意:如果在Nginx或者OpenResty的上层有用到阿里云的SLB负载均衡的话,需要修改一下脚本里的所有…ngx.var.remote_addr,把remote_addr替换成从SLB获取真实IP的字段即可,不然获取到的IP全都是阿里云SLB发过来的并且是处理过的IP,同时,这些IP全都是一个网段的,根本没有办法起到封禁的效果)。
完整的Lua脚本如下所示。
(2)在需要做访问限制的location里加两段代码即可,这里用刚才的/lua做演示
图片
主要是添加如下配置。
其中,set $business “lua” 是为了把IP放进Redis的时候标明是哪个location的,可以不加这个配置。
随后,重新reload配置。
(3)打开浏览器访问192.168.1.222/lua 并一直按F5刷新。
图片
随后,连接Redis,查看IP的访问计数。
发现redis已经在统计访问lua这个网页ip的访问次数了
图片
这个key的过期时间是30秒,如果30秒没有重复访问20次这个key就会消失,所以说正常用户一般不会触发这个封禁的脚本。
图片
当30秒内访问超过了20次,发现触发脚本了,变成了403
图片
再次查看Redis的key,发现多了一个lua-block-192.168.1.158,过期时间是300秒,就是说在300秒内这个ip无法继续访问192.168.1.222/lua这个页面了。
图片
过五分钟后再去访问这个页面,又可以访问了。
图片
这个脚本的目的很简单:一个IP如果在30秒内其访问次数达到20次则表明该IP访问频率太快了,因此将该IP封禁5分钟。同时由于计数的KEY在Redis中的超时时间设置成了30秒,所以如果两次访问间隔时间大于30秒将会重新开始计数。
大家也可以将这个脚本优化成,第一次封禁5分钟,第二次封禁半小时,第三次封禁半天,第四次封禁三天,第五次永久封禁等等。