После 2 дней изучения и понимания того, как работает Modsecurity, я наконец сделал это.К вашему сведению, я использую Apache 2.4.37 и Modsecurity 2.9.2 Вот что я сделал:
В моих пользовательских правилах файла: /etc/modsecurity/modsecurity_custom.conf
Я добавил следующее правило:
# Limit client hits by user agent
SecRule REQUEST_HEADERS:User-Agent "@pm facebookexternalhit" \
"id:400009,phase:2,nolog,pass,setvar:global.ratelimit_facebookexternalhit=+1,expirevar:global.ratelimit_facebookexternalhit=3"
SecRule GLOBAL:RATELIMIT_FACEBOOKEXTERNALHIT "@gt 1" \
"chain,id:4000010,phase:2,pause:300,deny,status:429,setenv:RATELIMITED,log,msg:'RATELIMITED BOT'"
SecRule REQUEST_HEADERS:User-Agent "@pm facebookexternalhit"
Header always set Retry-After "3" env=RATELIMITED
ErrorDocument 429 "Too Many Requests"
Объяснение:
Примечание. Я хочу ограничить 1 запрос каждые 3 секунды.
- Первое правило сопоставляет пользовательский агент заголовка запроса с "facebookexternalhit"».Если совпадение было успешным, оно создает свойство ratelimit_facebookexternalhit в коллекции global с начальным значением 1 (оно будет увеличивать это значение при каждом совпадении, совпадающем спользовательский агент).Затем он устанавливает время истечения этого вар в 3 секунды.Если мы получим новый хит, соответствующий «facebookexternalhit», то он будет равен 1 до ratelimit_facebookexternalhit.Если мы не получим совпадения, соответствующие «facebookexternalhit», через 3 секунды, ratelimit_facebookexternalhit пропадет, и этот процесс будет перезапущен.
- Если global.ratelimit_clients> 1 (мы получили 2 или более обращений в течение 3 секунд) ИПользовательский агент сопоставляет «facebookexternalhit» (это условие AND важно, потому что в противном случае все запросы будут отклонены, если будет произведено совпадение), мы устанавливаем RATELIMITED = 1, прекращаем действие с ошибкой 429 http и регистрируем пользовательское сообщение в журнале ошибок Apache: "RATELIMITED BOT".
- RATELIMITED = 1 устанавливается только для добавления пользовательского заголовка "Retry-After: 3".В этом случае эта переменная интерпретируется сканером Facebook (facebookexternalhit) и будет повторять операцию в указанное время.
- Мы отображаем настраиваемое возвращаемое сообщение (в случае необходимости) для ошибки 429.
Вы могли бы улучшить это правило, добавив @pmf и файл .data, а затем инициализировав глобальную коллекцию, например initcol:global=%{MATCHED_VAR}
, чтобы вы не ограничивались одним совпадением по правилу.Я не проверял этот последний шаг (это то, что мне было нужно прямо сейчас).Я обновлю свой ответ, если я это сделаю.
ОБНОВЛЕНИЕ :
Я адаптировал правило, чтобы иметь возможность иметь файл со всеми пользовательскими агентами, которые я хочучтобы ограничить скорость, можно использовать одно правило для нескольких ботов / сканеров:
# Limit client hits by user agent
SecRule REQUEST_HEADERS:User-Agent "@pmf data/ratelimit-clients.data" \
"id:100008,phase:2,nolog,pass,setuid:%{tx.ua_hash},setvar:user.ratelimit_client=+1,expirevar:user.ratelimit_client=3"
SecRule USER:RATELIMIT_CLIENT "@gt 1" \
"chain,id:1000009,phase:2,deny,status:429,setenv:RATELIMITED,log,msg:'RATELIMITED BOT'"
SecRule REQUEST_HEADERS:User-Agent "@pmf data/ratelimit-clients.data"
Header always set Retry-After "3" env=RATELIMITED
ErrorDocument 429 "Too Many Requests"
Итак, файл с пользовательскими агентами (по одному на строку) находится внутри подкаталога в том же каталоге этого правила: /etc/modsecurity/data/ratelimit-clients.data
.Затем мы используем @pmf для чтения и анализа файла (https://github.com/SpiderLabs/ModSecurity/wiki/Reference-Manual-(v2.x)#pmfromfile). Мы инициализируем коллекцию USER с помощью пользовательского агента: setuid:%{tx.ua_hash}
( tx.ua_hash находится в глобальной области действия в /usr/share/modsecurity-crs/modsecurity_crs_10_setup.conf
Мы просто используем user как коллекцию вместо global . Вот и все!