Openresty+Redis自动封禁访问频率过高IP

​在IP地址为w.w.w.w的服务器上安装nginx+luq+redis服务

实现思路:通过在Nginx上进行访问限制,通过Lua来灵活实现业务需求,而Redis用于存储黑名单列表。

Nginx+Lua+Redis安装

研究目标:nginx中使用lua脚本及nginx直接访问redis。

需要下载安装的内容:openresty和redis

第一步,安装编译工具及库文件,如果服务器上已经有了,可以不用再安装。

命令:yum install -y gcc gcc-c++ readline-devel pcre-devel openssl openssl-devel tcl perl make zlib zlib-devel libtool

第二步,采用OpenResty方式安装 Nginx+Lua模块。

OpenResty/ngx_openresty是一个全功能的 Web 应用服务器。它打包了标准的 Nginx 核心,很多的常用的第三方模块,以及它们的大多数依赖项。在网址:下载OpenResty。

命令:cd /usr/local/src

wget

tar xzvf openresty-1.19.3.2.tar.gz

mv openresty-1.19.3.2 openresty

cd openresty/

./configure --prefix=/usr/local/src/openresty/nginx

--with-luajit

make

make install

查看nginx版本命令:

/usr/local/src/openresty/nginx/sbin/nginx -v

或 /usr/local/src/openresty/nginx/sbin/nginx -V

结果显示“nginx version: openresty/1.19.3.2”,nginx就安装完成。

第三步,安装redis。

下载redis安装包命令:mkdir /usr/local/redisfile

cd /usr/local/redisfile

wget http://download.redis.io/releases/redis-4.0.10.tar.gz

解压安装包命令:tar zxvf redis-4.0.10.tar.gz

编译安装命令:cd redis-4.0.10

make

cd /usr/local/redisfile/redis-4.0.10/src

make install

Nginx+Lua+Redis配置

第一步,创建 Nginx 运行使用的用户nginx。

命令:useradd -s /sbin/nologin -M nginx

( Nginx 服务的默认用户是 nobody ,为了安全更改为 nginx,在配置文件中启用user nginx nginx;)

第二步,修改nginx配置文件。

配置nginx.conf文件,nginx.conf路径为/usr/local/src/openresty/nginx/conf/nginx.conf。文件内容如下:

user nginx nginx;  #用户名设置为刚刚创建的用户名
worker_processes  4; #允许生成的进程数,默认为1
worker_cpu_affinity 0001 0010 0100 1000;
error_log  /var/log/nginx/error.log info; #日志位置和级别
pid      /var/run/nginx.pid; #指定nginx进程运行文件存放地址
worker_rlimit_nofile 102400; #最大连接数,默认为512
events {
    use epoll; #事件驱动模型
    worker_connections 102400; #最大连接数,默认为512
    accept_mutex off; #设置网路连接序列化,防止惊群现象发生,默认为on
    multi_accept on; #设置一个进程是否同时接受多个网络连接,默认为off
}
http
{
    include mime.types;
    default_type application/octet-stream;
    ...
    server
    {
        listen 8080;  #监听端口
        server_name localhost;  #域名,当前IP地址
        charset utf-8;  #编码改为utf-8
        ...
}

第三步,修改redis配置文件。

1)为了方便管理,在/usr/local中新建/redis/etc文件夹,并在将/usr/local/redisfile/redis-4.0.10文件夹中的conf配置文件复制粘贴到/usr/local/redis/etc。原生的配置文件不用变,改完之后还能回到原来的样子,以保证安全。

命令:cp /usr/local/redisfile/redis-4.0.10/redis.conf /usr/local/redis/etc

2)在/usr/local中新建/redis/bin文件夹,/usr/local/redisfile/redis-4.0.10/src文件夹中的常用命令复制粘贴到/usr/local/redis/bin。

命令:cd /usr/local/redisfile/redis-4.0.10/src
cp mkreleasdhdr.sh redis-benchmark redis-check-aof redis-check-dump redis-cli redis-server /usr/local/redis/bin

3)redis开启访问权限的方法。

编辑配置/usr/local/redis/etc/redis.conf文件,修改“bind 127.0.0.1”为“bind 0.0.0.0”,再把“daemonize no”改为“daemonize yes”,“requirepass foobared”改为“requirepass 123456”,“dir ./”改为“dir /usr/local/redis/db”,“logfile ”改为“logfile /usr/local/redis/logs/redis.log”,保存并重启redis。

Nginx+Lua+Redis启动和访问站点

第一步,启动nginx。

命令:/usr/local/src/openresty/nginx/sbin/nginx

第二步,检查nginx是否已经启动。(查看是否有进程)

命令:ps -ef | grep nginx

结果的第一行显示“nginx:master process”,nginx已经启动。

注意:nginx:master process后面有一个路径,这就是nginx的安装路径。

第三步,访问nginx站点。

从浏览器访问已经配置好的站点IP,如果页面显示“Welcome to OpenResty!”,则说明OpenResty已经安装及配置好了。

第四步,关闭nginx。

命令:cd /usr/local/src/openresty/nginx/sbin

./nginx -s stop

第五步,配置文件修改后,需要指定配置文件进行nginx重启。

如果nginx服务已经停止,那就需要把nginx服务启动。

命令:/usr/local/src/openresty/nginx/sbin/nginx -c /usr/local/src/openresty/nginx/conf/nginx.conf

重启nginx服务必须是在nginx服务已经启动的情况下进行,因为这时,/usr/local/nginx/logs中存在nginx.pid文件。

命令:/usr/local/src/openresty/nginx/sbin/nginx -s reload

第六步,前台启动redis服务。

命令:cd /usr/local/redis/bin

./redis-server

注意:执行完该命令后,如果Lunix关闭当前会话,则redis服务也随即关闭。正常情况下,启动redis服务需要从后台启动,并且指定启动配置文件。

第七步,后台启动redis服务。

再次启动redis服务,并指定启动服务配置文件。

命令:cd /usr/local/redis/bin

./redis-server & #不会带上redis.conf配置文件启动

redis-server /usr/local/redis/etc/redis.conf

#结果第一行最后面显示redis端口

ps -ef | grep redis

#结果第一行最后面显示redis进程号

netstat -nap | grep 6379

服务端启动成功后,启动redis 客户端,查看端口号。

命令:redis-cli

auth 123456

set [key] [value]

get [key]

exit

netstat -nap | grep 6379

第八步,前台和后台关闭redis服务。

命令:cd /usr/local/redis/bin

pkill redis-server

redis-cli shutdown

netstat -nap | grep 6379

在Nginx中使用Lua脚本访问Redis

第一步,连接redis,然后添加一些测试参数。

命令:redis-cli

auth 123456

set "123" "456"

第二步,编写链接redis的Lua脚本。

在/usr/local/src/openresty/nginx/conf/lua中新建脚本文件redis.lua,在文件中写入下面的脚本:

local redis = require "resty.redis"

local conn = redis.new()

conn.connect(conn,'127.0.0.1','6379')

conn.auth('123456')

local res = conn:get("123")

if res==ngx.null then

    ngx.say("redis集群中不存在KEY——'123'")

    return

end

ngx.say(res)

第三步,编写访问控制的Lua脚本。

在/usr/local/src/openresty/nginx/conf/lua中新建脚本文件access.lua,在文件中写入下面的脚本:

local ip_block_time=300 --封禁IP时间(秒)

local ip_time_out=30    --指定ip访问频率时间段(秒)

local ip_max_count=20 --指定ip访问频率计数最大值(秒)

local BUSINESS = ngx.var.business --nginx的location中定义的业务标识符

--连接redis

local redis = require "resty.redis"

local conn = redis:new()

ok, err = conn:connect("127.0.0.1", 6379)

conn:set_timeout(2000) --超时时间2秒

ok, err = conn:auth("123456")

--如果连接失败,跳转到脚本结尾

if not ok then

    goto FLAG

end

--查询ip是否被禁止访问,如果存在则返回403错误代码

is_block, err = conn:get(BUSINESS.."-BLOCK-"..ngx.var.remote_addr)

if is_block == '1' then

    ngx.exit(403)

    goto FLAG

end

--查询redis中保存的ip的计数器

ip_count, err = conn:get(BUSINESS.."-COUNT-"..ngx.var.remote_addr)

if ip_count == ngx.null then --如果不存在,则将该IP存入redis,并将计数器设置为1、该KEY的超时时间为ip_time_out

    res, err = conn:set(BUSINESS.."-COUNT-"..ngx.var.remote_addr, 1)

    res, err = conn:expire(BUSINESS.."-COUNT-"..ngx.var.remote_addr, ip_time_out)

else

  ip_count = ip_count + 1 --存在则将单位时间内的访问次数加1

    if ip_count >= ip_max_count then --如果超过单位时间限制的访问次数,则添加限制访问标识,限制时间为ip_block_time

        res, err = conn:set(BUSINESS.."-BLOCK-"..ngx.var.remote_addr, 1)

        res, err = conn:expire(BUSINESS.."-BLOCK-"..ngx.var.remote_addr, ip_block_time)

    else

        res, err = conn:set(BUSINESS.."-COUNT-"..ngx.var.remote_addr,ip_count)

        res, err = conn:expire(BUSINESS.."-COUNT-"..ngx.var.remote_addr, ip_time_out)

    end

end

-- 结束标记

::FLAG::

local ok, err = conn:close()

第四步,在/usr/local/src/openresty/nginx/conf/nginx.conf中的http{}里面添加以下location。

location / {

            root   html;

            index  index.html index.htm;

}

location /lua {

              set $business "lua";

              access_by_lua_file /usr/local/src/openresty/nginx/conf/lua/access.lua;

              default_type text/plain;

              content_by_lua 'ngx.say("hello,lua!")';

}

location = /favicon.ico {

                   log_not_found off;

                   access_log off;

}

location /lua_redis {

                  default_type text/plain;

                  content_by_lua_file  /usr/local/src/openresty/nginx/conf/lua/redis.lua;

}

第五步,修改完nginx.conf后,重启nginx以及redis。

命令:cd /usr/local/src/openresty/nginx/sbin

./nginx -s stop

/usr/local/src/openresty/nginx/sbin/nginx -c /usr/local/src/openresty/nginx/conf/nginx.conf

/usr/local/src/openresty/nginx/sbin/nginx -s reload

ps -ef | grep nginx

cd /usr/local/redis/bin

pkill redis-server

./redis-server

redis-server /usr/local/redis/etc/redis.conf

ps -ef | grep redis

netstat -nap | grep 6379

第六步,访问w.w.w.w:8080/lua,并一直按F5刷新。

连接redis命令:

redis-cli

127.0.0.1:6379> auth 123456

127.0.0.1:6379> keys *

1)"lua-COUNT-115.150.246.33"

2)"lua-BLOCK-115.150.246.33"

127.0.0.1:6379> get "lua-COUNT-115.150.246.33"

"19"

127.0.0.1:6379> get "lua-COUNT-115.150.246.33"

(integer) 2

127.0.0.1:6379> get "lua-COUNT-115.150.246.33"

(integer) -2

发现redis已经在统计访问lua页面的访问次数。

这个key的过期时间是30秒,若30秒没有重复访问20次,则这个key就会消失。因此,正常用户一般不会触发这个封禁的脚本。

当30秒内访问lua页面超过20次,触发了封禁脚本,页面显示“403 Forbidden”时,连接redis结果显示"lua-BLOCK-115.150.246.33",那这个key的过期时间是300秒,即300秒内这个ip无法继续访问w.w.w.w:8080/lua页面。

这个脚本的目的:若一个IP在30秒内访问lua页面超过20次,则表明该IP访问频率太快,因此将该IP封禁5分钟。同时由于在redis中,key的超时时间设置为30秒,所以若两次访问间隔时间大于30秒,则将会重新开始计数。

关机重启,nginx会自动启动

第一步,修改/etc/rc.d/rc.local文件。

在/etc/rc.d/rc.local文件最后一行下面另起一行添加下面的代码:

/usr/local/src/openresty/nginx/sbin/nginx

第二步,给予/etc/rc.d/rc.local权限。

命令:cd /etc/rc.d

chmod +x /etc/rc.d/rc.local

第三步,服务器重启后,查看nginx是否成功自动启动。

与“nginx启动和访问站点”中的第二步和第三步一样操作。

命令:shutdown -r now 或 reboot 或 init 6 #立刻重启

shutdown -r 10 #过10分钟自动重启

关机重启,redis会自动启动

使用redis启动/usr/local/redisfile/redis-4.0.10/utils中的脚本redis_init_script设置开机自启动。

第一步,修改redis_init_script脚本代码。

redis_init_script脚本代码如下:

#!/bin/sh

...

REDISPORT=6379

#服务端所处位置

EXEC=/usr/local/redis/bin/redis-server

#客户端位置

CLIEXEC=/usr/local/redis/bin/redis-cli

#redis的PID文件位置,需要修改

PIDFILE=/var/run/redis_6379.pid

#redis的配置文件位置,需将${REDISPORT}修改为文件名

CONF="/usr/local/redis/etc/redis.conf"

...

第二步,将redis_init_script复制到/etc/rc.d/init.d目录下。

redis_init_script复制到/etc/rc.d/init.d,复制粘贴的启动脚本会被命名为redisd(通常都以d结尾表示是后台自启动服务)。

命令:cd /usr/local/redisfile/redis-4.0.10/utils

cp redis_init_script /etc/rc.d/init.d/redisd

chmod +x /etc/rc.d/init.d/redisd

#设置为开机自启动服务器

chkconfig redisd on

在设置开机自启动时,发现错误:

service redisd does not support chkconfig

这个错误的解决办法是在启动脚本开头添加如下注释来修改运行级别,如下:

#!/bin/sh

# chkconfig: 2345 90 10

再用命令:chkconfig redisd on设置即可。

不进入redis根目录即可进行相应的操作

打开服务:service redisd start

关闭服务:service redisd stop

不进入nginx根目录即可进行相应的操作

第一步,新建nginx启动脚本代码。

在文件夹/etc/init.d中新建名为nginx的文件,然后写入下面代码成为脚本文件。代码如下:

#!/bin/bash
# nginx Startup script for the Nginx HTTP Server
# it is v.0.0.2 version.
# chkconfig: - 85 15
# description: Nginx is a high-performance web and proxy server.
#              It has a lot of features, but it's not for everyone.
# processname: nginx
# pidfile: /var/run/nginx.pid
# config: /usr/local/nginx/conf/nginx.conf
nginxd=/usr/sbin/nginx
nginx_config=/etc/nginx/nginx.conf
nginx_pid=/var/run/nginx.pid
RETVAL=0
prog="nginx"
# Source function library.
. /etc/rc.d/init.d/functions
# Source networking configuration.
. /etc/sysconfig/network
# Check that networking is up.
[ ${NETWORKING} = "no" ] && exit 0
[ -x $nginxd ] || exit 0
# Start nginx daemons functions.
start() {
if [ -e $nginx_pid ];then
   echo "nginx already running...."
   exit 1
fi
   echo -n $"Starting $prog: "
   daemon $nginxd -c ${nginx_config}
   RETVAL=$?
   echo
   [ $RETVAL = 0 ] && touch /var/lock/subsys/nginx
   return $RETVAL
}
# Stop nginx daemons functions.
stop() {
        echo -n $"Stopping $prog: "
        killproc $nginxd
        RETVAL=$?
        echo
        [ $RETVAL = 0 ] && rm -f /var/lock/subsys/nginx /var/run/nginx.pid
}
# reload nginx service functions.
reload() {
    echo -n $"Reloading $prog: "
    #kill -HUP `cat ${nginx_pid}`
    killproc $nginxd -HUP
    RETVAL=$?
    echo
}
# See how we were called.
case "$1" in
start)
        start
        ;;
stop)
        stop
        ;;
reload)
        reload
        ;;
restart)
        stop
        start
        ;;
status)
        status $prog
        RETVAL=$?
        ;;
*)
        echo $"Usage: $prog {start|stop|restart|reload|status|help}"
        exit 1
esac
exit $RETVAL

第二步,给予/etc/init.d/nginx文件权限。

命令:chmod +x /etc/init.d/nginx

# 设置开机自启

命令:chkconfig --add nginx

chkconfig nginx on

# 检查nginx命令

命令:service nginx

/etc/init.d/nginx: line 20: [: =: unary operator expected

Usage: nginx {start|stop|restart|reload|status|help}

第三步,检查一下脚本是否有用。

命令:/sbin/chkconfig nginx on

sudo /sbin/chkconfig --list nginx

如果结果显示“nginx 0:off 1:off 2:on 3:on 4:on 5:on 6:off”,则说明脚本文件有用。

第四步,nginx启动、关闭以及重启命令。

ps -ef | grep nginx

systemctl start nginx

systemctl stop nginx

systemctl restart nginx

service nginx start

service nginx stop

service nginx restart

posted @ 2022-09-01 07:09  锐洋智能  阅读(287)  评论(0编辑  收藏  举报