nginx lua redisアクセス頻度制限

4045 ワード

1.需要分析
Nginxによるアクセス制御の処理方法は多様であり,実現効果も多様であり,IPセグメントへのアクセス,コンテンツへのアクセス制限,アクセス頻度制限などである.
Nginx+Lua+Redisでアクセス制限を行うのは,主に高同時環境での高速アクセス制御の必要性を考慮している.
Nginxが要求を処理するプロセスは全部で11段階に分けられ、それぞれ:
post-read、server-rewrite、find-config、rewrite、post-rewrite、 preaccess、access、post-access、try-files、content、log.
Openrestyでは、次の項目を見つけることができます.
set_by_lua,access_by_lua,content_by_lua,rewrite_by_luaなどの方法.
アクセス制御は、accessフェーズであるべきである.
ソリューション
通常の論理的思考に基づいて、アクセス制御スキームは次のように考えられます.
1.検出はforbidden?はい、forbiddenが期限切れかどうか:はい、レコードを消去し、200を返し、正常にアクセスします.いいえ、403を返します.=いいえ、200を返します.通常のアクセス
2.アクセス毎に、アクセスユーザのアクセス頻度+1処理
3.アクセス頻度が制限を超えているかどうかを検出し、forbiddenレコードを追加し、403に戻る
これは単純なスキームであり,点枝枝葉を追加することもでき,アクセス禁止時間はアルゴリズムによって導入され,毎回凹曲線が増加する.
実装方法
まずnginxにvhostプロファイル、vhostを追加する.confの部分は以下の通りです.
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
lua_package_path "/usr/local/openresty/lualib/?.lua;;";#Openrestyライブラリのアドレスを教えてください
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";#luaによるアクセス制御の処理
    }
}
 
Access_by_redis.lua
v 2 exを参照してください.comのやり方では、redisストレージスキームは簡単にstringストレージだけで十分です.keyはそれぞれ:
ユーザーログインレコード:user:127.0.0.1:time(unixタイムスタンプ)アクセス制限:block:127.0.0.1
まずRedisに接続しましょう.
 
1
2
3
4
5
6
7
8
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
我々の論理スキームによれば、第2のステップはforbiddenかどうかを検出することであり、次にblock:127.0.0.1を検出し、データが検索された場合、検出時間が期限切れであるかどうか、期限切れでない場合は403を返し、そうでない場合は直接200を返す.
 
1
2
3
4
5
6
7
8
9
10
11
12
13
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
}
次に、アクセス頻度が高すぎるかどうか、高すぎるとブラックリストに引っ張るかどうかを検出します.
実装方法は、user:127.0.0.1:timeの値が基準値を超えたかどうかを検出することである.
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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
最後に、訪問時間を1回に1つの自己成長を行うことを覚えておいてください.user:127.0.0.1:time:
 
1
2
3
4
5
6
7
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
では、テストして、ブラウザを何回か強くブラシして、しばらくして、403に戻って、ok、できました.
https://www.ttlsa.com/nginx/nginx-lua-redis-access-frequency-limit/