Two examples of nginx lua redis access frequency limit

Source: Internet
Author: User
Tags local time lua redis

1. Requirement analysis

There are many methods for Nginx to handle access control, and there are also many implementation effects, such as access IP segments, access content restrictions, and access frequency restrictions.
Using Nginx + Lua + Redis for access restrictions mainly takes into account the need for fast access control in high-concurrency environments.
The Nginx request processing process is divided into 11 stages:

Post-read, server-rewrite, find-config, rewrite, post-rewrite, preaccess, access, post-access, try-files, content, and log.
In openresty, you can find:

Set_by_lua, access_by_lua, content_by_lua, rewrite_by_lua, and other methods.
The access control should be in the access phase.

Solution

According to the normal logic, we will think of the following access control scheme:
1. Is it forbidden?
= "Yes, whether forbidden expires: Yes, clear the record, return 200, normal access; no, return 403;
= "No, 200 is returned for normal access
2. The access frequency of each access is + 1.
3. Check whether the access frequency has exceeded the limit. If the limit is exceeded, the forbidden record is added and 403 is returned.
This is a simple solution. You can also add branches and leaves. The access prohibition time is imported using algorithms, and each concave curve increases.

Implementation method

Add the vhost configuration file for nginx. The vhost. conf file is as follows:


Lua_package_path "/usr/local/openresty/lualib /?. Lua; "; # tell openresty Library address
Lua_package_cpath "/usr/local/openresty/lualib /?. So ;;";
Error_log/usr/local/openresty/nginx/logs/openresty. debug. log debug;
 
Server {
Listen 8080 default;
Server_name www.ttlsa.com;
Root/www/openresty;
 
Location/login {
Default_type 'text/html ';
Access_by_lua_file "/usr/local/openresty/nginx/lua/access_by_redis.lua"; # handle access control through lua
    }
}
Access_by_redis.lua

With reference to v2ex.com, it is enough to simply store strings in the redis storage solution. The keys are:
User logon record: user: 127.0.0.1: time (unix timestamp)
Access restriction: block: 127.0.0.1

Connect to Redis first:


Local red = redis: new ()
Function M: redis ()
Red: set_timeout (1000)
Local OK, err = red: connect ("127.0.0.1", 6379)
If not OK then
Ngx. exit (ngx. HTTP_INTERNAL_SERVER_ERROR)
End
End

According to our logic scheme, the second step is to check whether it is forbidden. Next we will check the block: 127.0.0.1. If the data is found, check whether the time has expired. If it has not expired, 403 is returned, otherwise, 200 is directly returned:

Function M: check1 ()
Local time = OS. time () -- system time
Local res, err = red: get ("block:"... ngx. var. remote_addr)
If not res then -- redis error
Ngx. exit (ngx. HTTP_INTERNAL_SERVER_ERROR) -- redis get data error end
 
If type (res) = "string" then -- if red not null then type (red) = string
If tonumber (res)> = tonumber (time) then -- check if forbidden expired
Ngx. exit (ngx. HTTP_FORBIDDEN)
-- Ngx. say ("forbidden ")
End
End
}

Next, we will check whether the access frequency is too high. If the access frequency is too high, we need to pull it to the blacklist,
The method is to check whether the value of user: 127.0.0.1: time is exceeded:

Function M: check2 ()
Local time = OS. time () -- system time
Local res, err = red: get ("user:"... ngx. var. remote_addr... ":"... time)
If not res then -- redis error
Ngx. exit (ngx. HTTP_INTERNAL_SERVER_ERROR) -- redis get data error
End
 
If type (res) = "string" then
If tonumber (res)> = 10 then -- attack, 10 times request/s
Red: del ("block:" .. self. ip)
Red: set ("block:" .. self. ip, tonumber (time) + 5*60) -- set block time
Ngx. exit (ngx. HTTP_FORBIDDEN)
End
End
End

Finally, remember to make a self-increasing access time, user: 127.0.0.1: time:

 

Function M: add ()
Local time = OS. time () -- system time
OK, err = red: incr ("user:"... ngx. var. remote_addr... ":"... time)
If not OK then
Ngx. exit (ngx. HTTP_INTERNAL_SERVER_ERROR) -- redis get data error
End
End
In the test, the browser will be refreshed several times. After a while, the system will return 403 and OK.

Example 2


I. Overview

Requirement: All Access/myapi/** requests must be POST requests, and illegal requests (blacklists) that do not comply with the rules are filtered based on the request parameters ), these requests are not forwarded to backend servers (Tomcat)

Implementation idea: access restrictions are imposed on Nginx, and Lua is used to flexibly meet business requirements. Redis is used to store the blacklist list.

 

II. Specific implementation

1. lua code

In this example, the restrictions include (post request, IP address blacklist, imsi in request parameters, tel value, and blacklist)

-- Access_by_lua_file '/usr/local/lua_test/my_access_limit.lua ';
Ngx. req. read_body ()

Local redis = require "resty. redis"
Local red = redis. new ()
Red. connect (red, '127. 0.0.1 ', '123 ')

Local myIP = ngx. req. get_headers () ["X-Real-IP"]
If myIP = nil then
MyIP = ngx. req. get_headers () ["x_forwarded_for"]
End
If myIP = nil then
MyIP = ngx. var. remote_addr
End
       
If ngx. re. match (ngx. var. uri, "^ (/myapi/). * $") then
Local method = ngx. var. request_method
If method = 'post' then
Local args = ngx. req. get_post_args ()
       
Local hasIP = red: sismember ('black. IP', myIP)
Local hasIMSI = red: sismember ('black. imsi ', args. imsi)
Local hasTEL = red: sismember ('black. Tel', args. tel)
If hasIP = 1 or hasIMSI = 1 or hasTEL = 1 then
-- Ngx. say ("This is 'black list' request ")
Ngx. exit (ngx. HTTP_FORBIDDEN)
End
Else
-- Ngx. say ("This is 'GET' request ")
Ngx. exit (ngx. HTTP_FORBIDDEN)
End
End
 

2. nginx. conf

Location /{
Root html;
Index index.html index.htm;

Access_by_lua_file/usr/local/lua_test/my_access_limit.lua;

Proxy_pass http: // 127.0.0.1: 8080;
Client_max_body_size 1 m;
}

3. Add blacklist rule Data

# Redis-cli sadd black. ip '2017. 34.118.50'
# Redis-cli sadd black. imsi '123'
# Redis-cli sadd black. tel '123'

 
You can use redis-cli smembers black. imsi to view the list details.
 
4. Verification results

# Curl-d "imsi = 460123456789 & tel = 15800000000" "http://www.mysite.com/myapi/abc"

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.