OpenResty динамически добавляет практику записи в черный список

Nginx
OpenResty динамически добавляет практику записи в черный список

В последнее время почему-то снова обратил внимание на сервер. В нашем сервере в качестве веб-сервера используется сам nginx.Хотя сам nginx поддерживает настройки текущего лимита и лимита ip, в настройке динамического черного списка сам nginx этого сделать не может. На этом этапе вы можете использовать OpenResty.

OpenResty

Про OpenResty, собственно онлайн и самкитайская домашняя страницаОн уже был представлен очень подробно, и я не буду объяснять их здесь по одному, единственное, что следует отметить, это то, что, поскольку сам OpenResty уже включает nginx, если nginx ранее использовался на сервере, текущая версия nginx должна сначала удалить. , а затем установить OpenResty, поэтому вам нужно остановить исходный сервис nginx и создать резервную копию предыдущего файла конфигурации, а затем установить его. Я установил его через yum, и конкретные инструкции использовали

# 删除原本的nginx,记得先备份配置
systemctl disable nginx.service
rm -rf /usr/lib/systemd/system/nginx.service
yum erase nginx 

# 安装 yum-utils 
yum install yum-utils
# yum 安装 openresty
yum install openresty

# 配置 nginx profile PATH
PATH=/usr/local/openresty/nginx/sbin:$PATH
export PATH
# 指定配置
nginx -c /usr/local/openresty/nginx/conf/nginx.conf 

На этом простая подготовка к OpenResty завершена, давайте посмотрим, как реализовать динамическую настройку черного списка через lua-скрипт.

Скрипт динамического черного списка

Прежде всего, поскольку на практике используются OpenResty и следующие компоненты redis, если вы не знакомы с lua и redis, вам необходимо иметь базовое представление о соответствующих знаниях.Здесь вы можете перейти к OpenResty для получения инструкций по компонентам redis и Компоненты nginx.

Тогда вот моя ссылка на космический полет[1]блогерэта статьяс небольшими корректировками.

В ходе этого процесса блогер дал мне много мнений и мнений, и терпеливо выслушал некоторые предложения и ответы с моей стороны, а также дал мне некоторые другие решения в плане эксплуатации и обслуживания.Большое спасибо здесь.

Ниже приведен код для обработки, первый — это код конфигурации:

set $redis_service "127.0.0.1";
set $redis_port 6380;
set $redis_db 0;
# 1 second 50 query
set $black_count 50;
set $black_rule_unit_time 1;
set $black_ttl 3600;
set $auto_blacklist_key blackkey;

Явного отличия от конфигурации в примере нет, поясним смысл каждой конфигурации отдельно:

  • redis_service: IP-адрес сервера Redis
  • redis_port: порт сервера Redis
  • redis_db: используемая база данных redis
  • black_count: максимальное количество посещений, ограниченное черным списком.
  • black_rule_unit_time: Время хранения лимита затемнения, то есть ttl кв, что сохраняет количество посещений
  • black_ttl: Время выживания черного списка, т.к. у меня здесь постоянный запас, поэтому он не используется
  • auto_blacklist_key: часть ключа kv

Устанавливается в соответствии с личными предпочтениями и потребностями, обычно достаточно управлять black_count и black_rule_unit_time.

Затем есть этот конкретный код сценария lua, большая часть которого также соответствует примеру:

local redis_service = ngx.var.redis_service
local redis_port = tonumber(ngx.var.redis_port)
local redis_db = tonumber(ngx.var.redis_db)
local black_count = tonumber(ngx.var.black_count)
local black_rule_unit_time = tonumber(ngx.var.black_rule_unit_time)
local cache_ttl = tonumber(ngx.var.black_ttl)
local remote_ip = ngx.var.remote_addr

-- 计数
function my_count(redis, status_key, count_key)
    local key = status_key
    local key_connect_count = count_key

    local Status = redis:get(key)
    local count = redis:get(key_connect_count)

    if Status ~= ngx.null then
        -- 状态为connect 且 count不为空 且 count <= 拉黑次数
        if (Status == "Connect" and count ~= ngx.null and tonumber(count) <= black_count) then
            -- 再读一次
            count = redis:incr(key_connect_count)
            ngx.log(ngx.ERR, "count:", count) 
            if count ~= ngx.null then
                if tonumber(count) > black_count then
                    redis:del(key_connect_count)
                    redis:set(key,"Black")
                    -- 永久封禁
                    -- Redis:expire(key,cache_ttl)
                else
                    redis:expire(key_connect_count,black_rule_unit_time)
                end
            end
        else
            ngx.log(ngx.ERR,"The visit is blocked by the blacklist because it is too frequent. Please visit later.")
            return ngx.exit(ngx.HTTP_FORBIDDEN)
        end
    else
        local count = redis:get(key)
        if count == ngx.null then
            redis:del(key_connect_count)
        end
        redis:set(key,"Connect")
        redis:set(key_connect_count,1)
        redis:expire(key,black_rule_unit_time)
        redis:expire(key_connect_count,black_rule_unit_time)
    end
end 

-- 读取token
local token
local header = ngx.req.get_headers()["Authorization"]
if header ~= nil then
    token = string.match(header, 'token (%x+)')
end

local redis_connect_timeout = 60
local redis = require "resty.redis"
local Redis = redis:new()
local auto_blacklist_key = ngx.var.auto_blacklist_key

Redis:set_timeout(redis_connect_timeout)

local RedisConnectOk,ReidsConnectErr = Redis:connect(redis_service,redis_port)
local res = Redis:auth("password");

if not RedisConnectOk then
    ngx.log(ngx.ERR,"ip_blacklist connect Redis Error :" .. ReidsConnectErr)
else
    -- 连接成功
    Redis:select(redis_db)

    local key = auto_blacklist_key..":"..remote_ip
    local key_connect_count = auto_blacklist_key..":key_connect_count:"..remote_ip

    my_count(Redis, key, key_connect_count)

    if token ~= nil then
        local token_key, token_key_connect_count
        token_key = auto_blacklist_key..":"..token
        token_key_connect_count = auto_blacklist_key..":key_connect_count:"..token
        my_count(Redis, token_key, token_key_connect_count)
    end
end

Т.к. я тоже отношусь к уровню новичка в практике lua, в структуре есть явные проблемы, так что оставим здесь дырку.

Сначала объясните этот код, потому что я начинаю с ip и токена (учетных данных доступа) для управления, поэтому сначала интегрируйте счетчик в эталонном примере в функцию. Исходный пример в функции заключается в использованииsetспособ добавить одну операцию, поэтому при поступлении большого количества запросов будет проблема с синхронизацией, поэтому я внесу здесь небольшую модификацию и воспользуюсьincrЧтобы выполнить операцию автоинкремента и при входе в метод получить значение счетчика и определить, превышает ли значение счетчика пороговое значениеblack_count, чтобы избежать проблемы большого количества запросов за раз.

Затем при получении токена ниже я получил авторизацию из заголовка в соответствии с методом учетных данных, используемым в приложении, и перехватил его, чтобы получить токен.Если токен пуст, это доказывает, что процесс подсчета токенов не требуется.

Последнее — это подключить и вызвать функцию, здесь объяснять нечего, главное — нужно обратить внимание на порядок определения и использования функции.

Затем он фактически выделяется в конфу nginx:

server {
  listen 80;
  server_name blog.mintrumpet.fun;
  root  /~/public;
  # 加载配置文件
  include /etc/nginx/conf.d/blacklist_params;
  # 指定请求中需要执行的 lua 脚本
  access_by_lua_file /etc/nginx/conf.d/ip_blacklist.lua;
  location / {
  }
  error_log /etc/nginx/conf.d/log/error.log;
  access_log /etc/nginx/conf.d/log/access.log;
}

Выше настройка завершена, перезапускаем nginx в консолиnginx -s reload, можно добиться необходимости динамического добавления в черный список. Что касается ip и токена, добавленных в черный список, то, как сделать следующий шаг, должно решаться конкретным приложением под сервером, что здесь не объясняется.

контрольная работа

Я использую свой личный сервер в процессеблог, и инструмент Apache для тестирования.

Сначала протестируйте пример без токена (посетитель), получите доступ к статическому файлу,

В качестве предела я взял 50 раз за 10 секунд, начиная с 4 одновременных обращений 40 раз:

ab -n 40 -c 4 http://blog.mintrumpet.fun/dist/music.js

В результате выполнения видно, что 40 запросов были выполнены успешно.

Посмотрите на значение под Redis,

Все в порядке, это еще не предельный размер.

Затем 4 одновременных доступа 100 раз:

ab -n 100 -c 4 http://blog.mintrumpet.fun/dist/music.js

Как видно из результатов, не удалось получить доступ к 49 запросам, и очевидно, что все они были переведены на 403.

Посмотрите на значение под Redis,

Очевидно мой айпи был заблокирован, а потом когда зашел в гости выдало ошибку 403, ОК, цель достигнута.

Далее давайте проверим пример токена, который также обращается к статическому файлу, и к нему также обращаются 100 раз по 4 одновременно:

ab -n 100 -c 4 -H "Authorization:token 87BF813C6DDB9C01D4525F47908D4C9F" http://blog.mintrumpet.fun/dist/music.js

Результат тот же, токен блокируется, последующие обращения тоже переадресовываются на 403.

На этом весь тест закончен, видно, что будь то туристический визит или визит для удостоверения личности, можно добиться одного и того же эффекта.

резюме

На самом деле, этот подход можно использовать только в общих ситуациях, и есть еще много областей для улучшения в написанных файлах конфигурации и сценариях.Я просто следую примеру здесь.Если у читателей есть лучшие практики и решения, вы можете сообщить читателю об этом в обсуждении ниже. В то же время, когда я общался с блогером Aerospace, он также сказал мне сделать другие обработки ограничения тока и перехвата для защиты от атак и мониторинга, такие как fail2ban, OSSEC и т. д. Да и сам nginx предоставляет ряд текущих ограничительных мер, и те, кому это интересно, могут изучить его самостоятельно.

На этом пока практика OpenResty закончилась, можете обратить внимание на мой блог[2] blog.mintrumpet.fun/илиРид ТехнологияПриходи и поговорим со мной о технологии, так что это конец дня. Наслаждайтесь кодированием!


Маленькие динамики

Команда разработчиков Java компании Guangzhou Reed Technology

Reed Technology-Guangzhou Professional Internet Software Service Company

Ухватитесь за каждую деталь и создайте каждую красоту

Подпишитесь на наш официальный аккаунт, чтобы узнать больше

Хотите сразиться с нами? лагу поиск"Рид Технология» или отправить свое резюме наserver@talkmoney.cnПрисоединяйтесь к нам

Следите за нами, ваши комментарии и лайки - наша самая большая поддержка


  1. снять пространство,www.qhjack.cn/ ↩︎

  2. маленький трубный домик,blog.mintrumpet.fun/ ↩︎