Есть ли способ, с помощью которого Nginx может уведомить меня, если количество обращений от реферера превышает порог?
Например, если мой веб-сайт размещен на Slashdot, и внезапно у меня наступает 2K обращений через час, я хочу получать уведомления, когда количество обращений превышает 1K в час.
Удастся ли это сделать в Nginx? Возможно без Луа? (так как мой продукт не скомпилирован lua)
Ответы:
Наиболее эффективное решение может быть , чтобы написать демон , который будет и следить за поле.
tail -f
access.log
$http_referer
Однако быстрым и грязным решением было бы добавить дополнительный
access_log
файл, чтобы регистрировать только$http_referer
переменную с пользовательским параметромlog_format
, и автоматически вращать журнал каждые X минут.Это может быть выполнено с помощью стандартных сценариев logrotate, которым может потребоваться постепенный перезапуск nginx для повторного открытия файлов (например, стандартная процедура, посмотрите на / a / 15183322 в SO для простого времени - сценарий)…
Или, используя переменные внутри
access_log
, возможно, извлекая мелкую спецификацию$time_iso8601
с помощью директивыmap
илиif
(в зависимости от того, куда вы хотите поместить своюaccess_log
).Таким образом, с учетом вышесказанного у вас может быть 6 файлов журнала, каждый из которых охватывает период в 10 минут
http_referer.Txx{0,1,2,3,4,5}x.log
, например, получая первую цифру минуты, чтобы различать каждый файл.Теперь все, что вам нужно сделать, это иметь простой сценарий оболочки, который может запускаться каждые 10 минут,
cat
все вышеперечисленные файлы вместе, передавать его поsort
конвейеруuniq -c
, направлять вsort -rn
, вhead -16
, и у вас есть список из 16 наиболее распространенныхReferer
вариантов. - свободно решать, если какие-либо комбинации чисел и полей превышает ваши критерии, и выполнить уведомление.Впоследствии, после одного успешного уведомления, вы можете удалить все эти 6 файлов и, при последующих запусках, не выдавать никаких уведомлений, ЕСЛИ НЕ присутствуют все шесть файлов (и / или определенный другой номер, который вы считаете нужным).
источник
Я думаю, что это было бы гораздо лучше сделать с logtail и grep. Даже если это возможно сделать с помощью lua inline, вы не хотите, чтобы эти накладные расходы использовались при каждом запросе, и особенно вы не хотите, чтобы это было, когда вы получили Slashdotted.
Вот 5-секундная версия. Вставьте это в сценарий и поместите немного более читабельного текста вокруг него, и вы - золотой.
Конечно, это полностью игнорирует reddit.com, facebook.com и все миллионы других сайтов, которые могут послать вам много трафика. Не говоря уже о 100 разных сайтах, каждый из которых отправляет по 20 посетителей. Вероятно, у вас должен быть простой старый порог трафика, который приводит к отправке вам электронного письма, независимо от реферала.
источник
-o
Опция предназначена для файла смещения, чтобы он знал, с чего начать чтение в следующий раз.Директива nginx limit_req_zone может основывать свои зоны на любой переменной, включая $ http_referrer.
Вы также захотите сделать что-то, чтобы ограничить количество состояния, требуемого на веб-сервере, поскольку заголовки реферера могут быть довольно длинными и разными, и вы можете увидеть бесконечное разнообразие. Вы можете использовать функцию nginx split_clients, чтобы установить переменную для всех запросов, основанную на хэше заголовка реферера. В приведенном ниже примере используется только 10 баксов, но вы можете сделать это с 1000 так же легко. Так что, если вы получили косую черту, люди, чей реферер хэшировал в тот же сегмент, что и URL-адрес slashdot, тоже будут заблокированы, но вы можете ограничить это до 0,1% посетителей, используя 1000 сегментов в split_clients.
Это будет выглядеть примерно так (полностью непроверено, но правильно):
источник
split_clients
могут быть неверно проинформированы - ониlimit_req
основаны на «утечке памяти», что означает, что общее состояние никогда не должно превышать размер указанной зоны.Да, конечно, это возможно в NGINX!
Что вы могли бы сделать, это реализовать следующий DFA :
Реализуйте ограничение скорости, основываясь на
$http_referer
возможном использовании некоторого регулярного выражения через amap
для нормализации значений. Когда лимит превышен, возникает внутренняя страница с ошибкой, которую можно перехватить с помощьюerror_page
обработчика по соответствующему вопросу , перейдя в новое внутреннее местоположение в качестве внутреннего перенаправления (невидимого для клиента).В указанном выше месте для превышенных пределов вы выполняете запрос оповещения, позволяя внешней логике выполнять уведомление; этот запрос впоследствии кэшируется, гарантируя, что вы получите только 1 уникальный запрос за данное временное окно.
Перехватите код состояния HTTP предыдущего запроса (вернув код состояния ≥ 300 и используя
proxy_intercept_errors on
или, альтернативно, используя не встроенный по умолчаниюauth_request
илиadd_after_body
сделать «бесплатный» подзапрос), и завершите исходный запрос, как если бы предыдущий шаг не был вовлечен. Обратите внимание, что для этого нужно включить рекурсивнуюerror_page
обработку.Вот мой PoC и MVP, также по адресу https://github.com/cnst/StackOverflow.cnst.nginx.conf/blob/master/sf.432636.detecting-slashdot-effect-in-nginx.conf :
Обратите внимание, что это работает как ожидалось:
Вы можете видеть, что первый запрос приводит к одному обращению к интерфейсу и одному бэкенду, как и ожидалось (мне пришлось добавить фиктивный бэкенд в расположение, которое имеет
limit_req
, поскольку areturn 200
будет иметь приоритет над ограничениями, настоящий бэкэнд не нужен для остальной обработки).Второй запрос превышает лимит, поэтому мы отправляем предупреждение (получение
200
) и кешируем его, возвращая429
(это необходимо из-за вышеупомянутого ограничения, что запросы ниже 300 не могут быть перехвачены), которое впоследствии перехватывается внешним интерфейсом , который теперь свободен, свободен делать все, что захочет.Третий запрос все еще превышает лимит, но мы уже отправили предупреждение, поэтому новое уведомление не отправляется.
Выполнено! Не забудьте раскошелиться на GitHub!
источник
limit_req
, а другой - alimit_conn
, то просто используйтеlimit_req_status 429
вышеупомянутое (требуется очень новый nginx), и я думаю, что вы должны быть золотым; возможны и другие варианты (один из которых наверняка сработает - это связывание nginx с /set_real_ip_from
, но, в зависимости от того, что именно вы хотите сделать, могут быть более эффективные варианты).golang
, или посмотреть опции тайм-аута для апстримов; также, возможно, захочет использоватьproxy_cache_lock on
, и, возможно, добавить некоторую обработку ошибок для того, что делать в случае сбоя сценария (например, используя,error_page
а такжеproxy_intercept_errors
снова). Я верю, что мой POC - хорошее начало. :)limit_req
/limit_conn
? Например, просто поместите вышеуказанный конфиг перед вашим текущим интерфейсным сервером. Вы могли бы использоватьset_real_ip_from
в восходящем nginx, чтобы гарантировать, что IP-адреса правильно учтены. Иначе, если он все еще не подходит, я думаю, что вы должны четко сформулировать свои точные ограничения и спецификацию - о каких уровнях трафика мы говорим? Как часто нужно запускать статистику (1 мин / 5 мин / 1 ч)? Что не так со старымlogtail
решением?