At present, a production system is frequently captured by crawlers, which has seriously affected the use of normal users, so we need to find ways to reduce these malicious requests. I originally thought to use Nginx’s built-in parameters to limit, but after testing, it didn’t work. Hence the decision to use Lua+Redis to limit the frequency of IP access and hence this article

I. Technical Preparation

(1) Lua programming in Nginx:

I chose to install OpenResty at this point. OpenResty, also known as “ngx_OpenResty”, is an Nginx-centric Web application server with many third-party modules. On Linux under OpenResty reference before I can install and use of this article: www.zifangsky.cn/1020.html

In addition, the basic usage of the using the Lua programming in Nginx can refer to my earlier this article: www.zifangsky.cn/1024.html

(2) Number of access times of a single IP address in a unit time:

Because the amount of data saved is small and the time saved is short (30 seconds automatically expires), I chose the most commonly used Redis. About Redis installation of single node can refer to my earlier this article: www.zifangsky.cn/823.html

Code implementation and testing

(1) Add access control Lua script:

[root@hbase31 ~]# vim /usr/local/openresty/nginx/conf/lua/access.luaCopy the code

It reads as follows:

Local ip_block_time=300 -- IP address blocking duration (s) Local ip_time_out=30 -- IP address access frequency period (s) local ip_max_count=20 -- Maximum IP address access frequency count (s) local BUSINESS = ngx.var. BUSINESS -- BUSINESS identifier defined in nginx's location -- connect to redis local redis = require "resty.redis" local conn = Redis :new() OK, err = conn:connect("192.168.1.30", 6379) conn:set_timeout(2000) -- timeout interval 2 seconds -- If the connection fails, If not OK then goto FLAG end -- Check whether the IP address is forbidden. If yes, return 403 error code is_block, err = conn:get(BUSINESS.." -BLOCK-".. Ngx.var. remote_addr) if is_block == '1' then ngx.exit(403) goto FLAG end err = conn:get(BUSINESS.." -COUNT-".. Ngx.var.remote_addr) if ip_count == ngx.null then 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 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()Copy the code

The purpose of this script is simple: an IP address that gets 20 visits in 30 seconds is too frequently accessed, so block it for 5 minutes. Since the timeout of the KEY count is set to 30 seconds in Redis, the count will be restarted if the interval between two accesses is longer than 30 seconds

(2) Reference the above script in the location where Nginx needs speed limits:

    location /user/ {
    set $business "USER";
    access_by_lua_file /usr/local/openresty/nginx/conf/lua/access.lua;
        proxy_redirect off;
        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_pass http://user_224/user/;
    }Copy the code

Note: For the front-end page with a large number of static resource files (such as JS, CSS, images, etc.), you can set the access rate limit only for the requests in the specified format. The example code is as follows:

    location /h5 {
        if ($request_uri ~ .*\.(html|htm|jsp|json)) {
            set $business "H5";
            access_by_lua_file /usr/local/openresty/nginx/conf/lua/access.lua;
        }
        proxy_redirect off;
        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_pass http://h5_224/h5;
    }Copy the code

(3) Test:

In the browser visit: http://192.168.1.31:3000/user/services, you can find can browse:

At this point, login to Redis and you can see that the counting has started:

Then use the F5 to refresh the page http://192.168.1.31:3000/user/services can be found after several times the browser display 403 pages, and then has been to 5 minutes before I can visit again

Reference:

  • Blog.csdn.net/u011579004/…