
この投稿は、
nginxでのluaの使用の続きです 。
メモリでのキャッシュについて説明しました。ここでは、luaを使用して、着信リクエストをnginx-balancerの一種のファイアウォールとしてフィルタリングします。
2GISには似たようなものがありました 。 独自の自転車を持っています:)ダイナミクスとスタティックを共有するために、NATとホワイトリストを考慮に入れます。 そして、もちろん、既製のモジュールを使用すると機能しない特定のロジックをいつでも入手できます。
このスキームは静かで楽になり(実際にはCPUの使用には影響しません)、約1200リクエスト/秒を処理します。 制限値はテストされていません。 おそらく、幸いなことに:)
access_logの行(同じ静的変数ではまだオフになっていると思われる)の事実ではなく、受信するとすぐにすべての着信要求を処理したいと思います。 間違いなく、http全体に対してハンドラーをグローバルに切断します。
http { include lua/req.conf; }
これで、nginxへのすべてのリクエストはreq.luaスクリプトを通過します。
同時に、リクエストの履歴を保存するための2つのテーブルreq_limitとban_listと、それに応じて既に禁止されているリストがあります(詳細は以下)。
また、自転車の代わりにIP経由でホワイトリストを実装するために、geo nginxモジュールが使用され、lua_req_whitelist変数の値が次のように使用されました。
if ngx.var.lua_req_whitelist ~= '1' then
静的/動的(ディスク/バックエンドサーバー上のファイルの要求)を確認するには、要求されたファイルの名前を簡単に確認します(ここで、ビジネスロジックに適応することで実装を複雑にできます)。
function string.endswith(haystack, needle) return (needle == '') or (needle == string.sub(haystack, -string.len(needle))) end local function path_is_static(path) local exts = {'js', 'css', 'png', 'jpg', 'jpeg', 'gif', 'xml', 'ico', 'swf'} path = path:lower() for _,ext in ipairs(exts) do if path:endswith(ext) then return true end end return false end local uri_path = ngx.var.request_uri if ngx.var.is_args == '?' then uri_path = uri_path:gsub('^([^?]+)\\?.*$', '%1') end local is_static = path_is_static(uri_path)
少なくとも一部のNAT処理では、IPクライアントに加えて、そのUserAgentも考慮され、特別なCookieが追加されます。 3つの要素全体がユーザーIDを構成します。 悪役が送信されたCookieを無視してサーバーを空洞化した場合、最悪の場合、そのIP /サブネットは禁止されます。 同時に、すでにCookieを受け取っているこのサブネットのユーザーは、静かにさらに動作します(IPの禁止の場合を除く)。 ソリューションは完璧ではありませんが、国/携帯電話会社の半分を1人のユーザーとして数えるよりも優れています。
Cookieの生成と検証:
local function gen_cookie_rand() return tostring(math.random(2147483647)) end local function gen_cookie(prefix, rnd) return ngx.encode_base64(
これで、key_prefixには、リクエストを処理しているクライアントの識別子が含まれます。 このクライアントがすでに禁止されている場合、それ以上の処理は不要です。
local ban_key = key_prefix..':ban' if ban_list:get(ban_key) or ban_list:get(ip..':ban') then
キーを取得し、禁止を確認しました。これで、このリクエストがどの制限を超えていないかを計算できます。
カウンターの4つのバージョンをチェックします:静的/動的、1つのパス/異なる。 直接チェックはcheck_limit_exhaust()で実行されます:
local function check_limit_exhaust(key, limit, cnt_ttl) local key_ts = key..':ts' local cnt, _ = req_limit:incr(key, 1)
lua_req_ban_ttl秒の直接禁止に加えて、永続的なストレージを実装し、同時にIPによって禁止されたロギングとフォワーディングをiptables /アナログに固定できます。 これはすでに話題外です。
もちろん、これはすべて単なる例であり、銀のコピーペーストではありません。 さらに、指定された数の制限が天井から示されます。
ヘッダーの画像はここから取得されます 。