
Высокопроизводительный WAF, построенный на стеке OpenResty
lua-resty-waf - высокопроизводительный WAF, построенный на стеке OpenResty
ПРИМЕЧАНИЕ: lua-resty-waf по сути заброшен. Этот проект был полезен в то время, когда ModSecurity для Nginx не был жизнеспособным вариантом; сейчас это уже не так. В 2020 году была попытка оживить проект, но у меня нет ресурсов, чтобы завершить её; эта работа частично выполнена в ветке redux.
lua-resty-waf - это обратный прокси-WAF, построенный на стеке OpenResty. Он использует Nginx Lua API для анализа информации HTTP-запросов и обработки на основе гибкой структуры правил. lua-resty-waf распространяется с набором правил, имитирующим ModSecurity CRS, а также с несколькими пользовательскими правилами, созданными в ходе первоначальной разработки и тестирования, и небольшим виртуальным набором исправлений для новых угроз. Кроме того, lua-resty-waf распространяется с инструментарием для автоматического перевода существующих правил ModSecurity, что позволяет пользователям расширять реализацию lua-resty-waf без необходимости изучать новый синтаксис правил.
lua-resty-waf был первоначально разработан Робертом Папроцки (Robert Paprocki) для его магистерской диссертации в Western Governor's University.
lua-resty-waf требует несколько сторонних модулей resty lua, хотя все они поставляются вместе с lua-resty-waf, и поэтому их не нужно устанавливать отдельно. Рекомендуется устанавливать lua-resty-waf на систему с программным пакетом OpenResty; lua-resty-waf не тестировался на платформах, собранных с использованием отдельных пакетов исходного кода Nginx и модуля Nginx Lua.
Для оптимальной производительности компиляции регулярных выражений рекомендуется собирать Nginx/OpenResty с версией PCRE, поддерживающей JIT-компиляцию. Если ваша ОС не предоставляет такой версии, вы можете собрать PCRE с поддержкой JIT непосредственно в вашу сборку Nginx/OpenResty. Для этого укажите путь к исходному коду PCRE в флаге конфигурации --with-pcre. Например:```sh
Вы можете загрузить исходный код PCRE с [сайта PCRE](http://www.pcre.org/). Также смотрите этот [пост в блоге](https://www.cryptobells.com/building-openresty-with-pcre-jit/) с пошаговым руководством по сборке OpenResty с библиотекой PCRE с поддержкой JIT.
## Производительность
lua-resty-waf проектировался с учётом эффективности и масштабируемости. Он использует асинхронную модель обработки Nginx и эффективную архитектуру, чтобы обрабатывать каждую транзакцию как можно быстрее. Нагрузочное тестирование показало, что развёртывания, использующие все предоставляемые наборы правил, которые призваны имитировать логику ModSecurity CRS, обрабатывают транзакции примерно за 300–500 микросекунд на запрос; это соответствует производительности, заявленной для [WAF Cloudflare](https://www.cloudflare.com/waf). Тесты проводились на разумном аппаратном стеке (CPU E3-1230, 32 ГБ ОЗУ, 2 x 840 EVO в RAID 0), достигая примерно 15 000 запросов в секунду. Более подробную информацию см. в [этом посте в блоге](http://www.cryptobells.com/freewaf-a-high-performance-scalable-open-web-firewall).
## Установка
Предоставляется простой Makefile:```
# make && sudo make install
Как вариант, установите через Luarocks:```
lua-resty-waf использует пакетный менеджер [OPM](https://github.com/openresty/opm), доступный в современных дистрибутивах OpenResty. Клиентские инструменты OPM требуют, чтобы инструмент командной строки `resty` был доступен в переменной окружения `PATH` вашей системы.
Обратите внимание, что по умолчанию lua-resty-waf работает в режиме SIMULATE, чтобы немедленно не влиять на приложение; пользователи, желающие включить действия правил, должны явно установить рабочий режим в ACTIVE.
## Synopsis```lua
http {
init_by_lua_block {
-- use resty.core for performance improvement, see the status note above
require "resty.core"
-- require the base module
local lua_resty_waf = require "resty.waf"
-- perform some preloading and optimization
lua_resty_waf.init()
}
server {
location / {
access_by_lua_block {
local lua_resty_waf = require "resty.waf"
local waf = lua_resty_waf:new()
-- define options that will be inherited across all scopes
waf:set_option("debug", true)
waf:set_option("mode", "ACTIVE")
-- this may be desirable for low-traffic or testing sites
-- by default, event logs are not written until the buffer is full
-- for testing, flush the log buffer every 5 seconds
--
-- this is only necessary when configuring a remote TCP/UDP
-- socket server for event logs. otherwise, this is ignored
waf:set_option("event_log_periodic_flush", 5)
-- run the firewall
waf:exec()
}
header_filter_by_lua_block {
local lua_resty_waf = require "resty.waf"
-- note that options set in previous handlers (in the same scope)
-- do not need to be set again
local waf = lua_resty_waf:new()
waf:exec()
}
body_filter_by_lua_block {
local lua_resty_waf = require "resty.waf"
local waf = lua_resty_waf:new()
waf:exec()
}
log_by_lua_block {
local lua_resty_waf = require "resty.waf"
local waf = lua_resty_waf:new()
waf:exec()
}
}
}
}
Преобразует и инициализирует файл правил ModSecurity SecRules с диска. Обратите внимание, что набор правил по-прежнему необходимо добавить через add_ruleset (в качестве ключа должно быть указано базовое имя файла).
Пример:```lua http { init_by_lua_block { local lua_resty_waf = require "resty.waf"
-- this translates and calculates a ruleset called 'ruleset_name'
local ok, errs = pcall(function()
lua_resty_waf.load_secrules("/path/to/secrules/ruleset_name")
end)
-- errs is an array-like table
if errs then
for i = 1, #errs do
ngx.log(ngx.ERR, errs[i])
end
end
}
server {
location / {
access_by_lua_block {
local lua_resty_waf = require "resty.waf"
local waf = lua_resty_waf:new()
-- in order to use the loaded ruleset, it must be added via
-- the 'add_ruleset' option
waf:set_option("add_ruleset", "ruleset_name")
}
}
}
}
Кроме того, `load_secrules` может принимать необязательный второй аргумент в виде таблицы параметров для передачи различным функциям перевода. Распознаются следующие параметры:
* *path*: Задаёт путь в файловой системе для поиска файлов данных для операторов, таких как @pmFromFile. Если такой ключ не задан, используется текущий рабочий каталог (`.`)
* *force*: Не выдавать ошибку и не прерывать выполнение при сбое перевода переменной правила
* *loose*: Не выдавать ошибку и не прерывать выполнение при сбое перевода действия правила
* *quiet*: Не выдавать ошибок и предупреждений при сбое перевода действия правила
Эта функция также может принимать третий аргумент в виде таблицы для сбора ошибок перевода с целью последующей обработки. Если этот аргумент отсутствует или не является таблицей, ошибки перевода вместо этого будут записаны в журнал ошибок.
### lua-resty-waf.init()
Выполняет некоторые предварительные вычисления правил и наборов правил на основе того, что было предоставлено через распространяемые по умолчанию наборы правил. Рекомендуется, но не обязательно, вызывать эту функцию (если этого не сделать, производительность немного снизится). Эту функцию не следует вызывать вне данной области.
*Пример*:```lua
http {
init_by_lua_block {
local lua_resty_waf = require "resty.waf"
lua_resty_waf.init()
}
}
Создайте новый экземпляр lua-resty-waf. Вы должны вызывать этот метод в каждой фазе обработчика запросов, в которой хотите запустить lua-resty-waf, и использовать возвращаемый результат для вызова последующих методов объекта.
Пример:```lua location / { access_by_lua_block { local lua_resty_waf = require "resty.waf"
local waf = lua_resty_waf:new()
}
}
### lua-resty-waf:set_option()
Настройте опцию для каждой области отдельно.
*Пример*:```lua
location / {
access_by_lua_block {
local lua_resty_waf = require "resty.waf"
local waf = lua_resty_waf:new()
-- enable debug logging only for this scope
waf:set_option("debug", true)
}
}
Определите переменную транзакции (хранящуюся в коллекции переменных TX) перед выполнением WAF. Это можно использовать для определения переменных, используемых сложными наборами правил, такими как OWASP CRS.
Пример:```lua location / { access_by_lua_block { local lua_resty_waf = require "resty.waf"
local waf = lua_resty_waf:new()
waf:set_var("FOO", "bar")
}
}
Обратите внимание, что, как и в случае с любым другим правилом ModSecurity, наличие переменной не вносит функциональных изменений в обработку WAF; ответственность за понимание и использование переменных `TX` несёт автор правила.
### lua-resty-waf:sieve_rule()
Определяет исключение коллекции для заданного правила.
*Пример*:```lua
location / {
access_by_lua_block {
local lua_resty_waf = require "resty.waf"
local waf = lua_resty_waf:new()
local sieves = {
{
type = "ARGS",
elts = "foo",
action = "ignore",
}
}
waf:sieve_rule("12345", sieves)
}
}
См. вики-страницу сита правил для подробностей и примеров расширенного использования.
Запускает движок правил. По умолчанию движок выполняется в соответствии с текущей фазой. Можно передать необязательную таблицу, позволяющую пользователям "имитировать" выполнение другой фазы.
Пример:```lua location / { access_by_lua_block { local lua_resty_waf = require "resty.waf"
local waf = lua_resty_waf:new()
-- execute according to access phase collections and rules
waf:exec()
}
content_by_lua_block {
local lua_resty_waf = require "waf"
local waf = lua_resty_waf:new()
-- execute header_filter rules, passing in a table of additional collections
-- this assumes the 'request_headers' and 'status' Lua variables were
-- declared and initialized elsewhere
local opts = {
phase = 'header_filter',
collections = {
REQUEST_HEADERS = request_headers,
STATUS = status,
}
}
waf:exec(opts)
}
}
### lua-resty-waf:write_log_events()
Записывает все записи журнала аудита, созданные в ходе транзакции. Вызов этой функции является необязательным только тогда, когда `exec` вызывается в обработчике `log_by_lua`.
*Пример*:```lua
location / {
log_by_lua_block {
local lua_resty_waf = require "resty.waf"
local waf = lua_resty_waf:new()
-- write out any event log entries to the
-- configured target, if applicable
waf:write_log_events()
}
}
По умолчанию: none
Добавляет дополнительный набор правил, используемый во время обработки. Это позволяет пользователям реализовывать собственные наборы правил, не затрагивая встроенный каталог правил. Дополнительные наборы правил должны находиться в папке "rules", расположенной внутри lua_package_path.
Пример:```lua http { -- the rule file 50000.json must live at -- /path/to/extra/rulesets/rules/50000.json lua_package_path '/path/to/extra/rulesets/?.lua;;';
server {
location / {
access_by_lua_block {
waf:set_option("add_ruleset", "50000_extra_rules")
}
}
}
}
Несколько наборов правил можно добавить, передав таблицу значений в `set_option`. Обратите внимание, что имена наборов правил сортируются перед обработкой. Наборы правил обрабатываются в отсортированном порядке по возрастанию.
### add_ruleset_string
*По умолчанию*: none
Добавляет дополнительный набор правил для использования при обработке. Это позволяет пользователям создавать собственные наборы правил, не затирая входящий в комплект каталог правил. Наборы правил определяются инлайн в виде Lua-строки в форме JSON-структуры транслированного набора правил.
*Пример*:```lua
location / {
access_by_lua_block {
waf:set_option("add_ruleset_string", "70000_extra_rules", [=[{"access":[{"action":"DENY","id":73,"operator":"REGEX","opts":{},"pattern":"foo","vars":[{"parse":{"values":1},"type":"REQUEST_ARGS"}]}],"body_filter":[],"header_filter":[]}]=])
}
}
Обратите внимание, что имена наборов правил сортируются перед обработкой и должны задаваться как строки. Наборы правил обрабатываются в порядке возрастания.
По умолчанию: false
Указывает lua-resty-waf продолжать обработку запроса, когда был отправлен заголовок Content-Type, который отсутствует в таблице allowed_content_types. Тело таких запросов не будет обрабатываться lua-resty-waf (коллекция REQUEST_BODY будет равна nil). Таким образом, пользователям не нужно явно добавлять в белый список все возможные заголовки Content-Type, с которыми они могут столкнуться.
Пример:```lua location / { access_by_lua_block { waf:set_option("allow_unknown_content_types", true) } }
### allowed_content_types
*По умолчанию*: none
Определяет один или несколько заголовков Content-Type, которые будут разрешены, в дополнение к типам контента по умолчанию `application/x-www-form-urlencoded` и `multipart/form-data`. Запрос, чей тип контента совпадает с одним из значений `allowed_content_types`, установит коллекцию `REQUEST_BODY` в одну строку, содержащую (а не таблицу); запрос, чей тип контента не совпадает ни с одним из этих значений, ни с `application/x-www-form-urlencoded`, ни с `multipart/form-data`, будет отклонён.
*Пример*:```lua
location / {
access_by_lua_block {
-- define a single allowed Content-Type value
waf:set_option("allowed_content_types", "text/xml")
-- defines multiple allowed Content-Type values
waf:set_option("allowed_content_types", { "text/html", "text/json", "application/json" })
}
}
Обратите внимание, что множественные вызовы set_option с параметром allowed_content_types просто переопределяют существующую таблицу опций, поэтому, если вы хотите определить несколько разрешённых типов контента, вы должны определить их в виде Lua-таблицы, как показано выше.
Default: false
Отключает/включает отладочное журналирование. Отладочные сообщения журнала выводятся в error_log. Обратите внимание, что отладочное журналирование очень ресурсозатратно и не должно использоваться в производственных средах.
Пример:```lua location / { access_by_lua_block { waf:set_option("debug", true) } }
### debug_log_level
*По умолчанию*: ngx.INFO
Задает константу уровня журналирования nginx, используемую для отладочного журналирования.
*Пример*:```lua
location / {
access_by_lua_block {
waf:set_option("debug_log_level", ngx.DEBUG)
}
}
По умолчанию: ngx.HTTP_FORBIDDEN
Задаёт статус, используемый при отклонении запросов.
Пример:```lua location / { access_by_lua_block { waf:set_option("deny_status", ngx.HTTP_NOT_FOUND) } }
### disable_pcre_optimization
*По умолчанию*: false
Удаляет флаги `oj` из всех вызовов `ngx.re.match`, `ngx.re.find` и `ngx.re.sub`. Это может быть полезно в некоторых случаях, когда используются старые библиотеки PCRE, но вызовет серьёзную деградацию производительности, поэтому использование этой опции настоятельно не рекомендуется; вместо этого пользователям рекомендуется собрать OpenResty с современной библиотекой PCRE, поддерживающей JIT.
*Пример*:```lua
location / {
access_by_lua_block {
waf:set_option("disable_pcre_optimization", true)
}
}
Примечание: это поведение устарело и будет удалено в будущих версиях.
По умолчанию: true
Определяет, следует ли записывать в журнал события о совпадениях с правилами в транзакции, которая не была изменена lua-resty-waf. «Изменена» означает, что lua-resty-waf применил правило, действие которого — ACCEPT или DENY. Если этот параметр не задан, lua-resty-waf будет записывать совпадения с правилами, даже если транзакция не была изменена. По умолчанию lua-resty-waf записывает события только для совпадений, если транзакция была изменена.
Пример:```lua location / { access_by_lua_block { waf:set_option("event_log_altered_only", false) } }
Обратите внимание, что `mode` не влияет на определение того, считается ли транзакция изменённой. То есть, если правило с действием `DENY` совпало, но lua-resty-waf работает в режиме `SIMULATE`, транзакция всё равно будет считаться изменённой, а совпадения правил будут записаны в журнал.
### event_log_buffer_size
*По умолчанию*: 4096
Определяет пороговый размер буфера в байтах, используемого для хранения журналов событий. Буфер будет сбрасываться при достижении этого порога.
*Пример*:```lua
location / {
access_by_lua_block {
-- 8 KB event log message buffer
waf:set_option("event_log_buffer_size", 8192)
}
}
По умолчанию: ngx.INFO
Задаёт константу уровня журналирования nginx, используемую для журналирования событий.
Пример:```lua location / { access_by_lua_block { waf:set_option("event_log_level", ngx.WARN) } }
### event_log_ngx_vars
*Default*: пусто
Определяет, какие дополнительные переменные из `ngx.var` попадают в событие журнала. Это универсальный способ расширить оповещение дополнительным контекстом. Имя переменной будет ключом записи внутри ключа `ngx` в записи журнала. Если переменная не существует как переменная nginx, то в событие ничего не добавляется.
*Пример*:```lua
location / {
access_by_lua_block {
waf:set_option("event_log_ngx_vars", "host")
waf:set_option("event_log_ngx_vars", "request_id")
}
}
Результирующее событие содержит эти дополнительные элементы:```json { "ngx": { "host": "example.com", "request_id": "373bcce584e3c18a" } }
### event_log_periodic_flush
*По умолчанию*: none
Определяет интервал в секундах, через который буфер журнала событий будет периодически сбрасываться. Если значение не задано, буфер не будет сбрасываться периодически и будет сбрасываться только при достижении порога `event_log_buffer_size`. Настройте этот параметр для сайтов с очень низким трафиком, которые могут не получать данные журнала событий в течение длительного периода времени, чтобы предотвратить хранение устаревших данных в буфере.
*Пример*:```lua
location / {
access_by_lua_block {
-- flush the event log buffer every 30 seconds
waf:set_option("event_log_periodic_flush", 30)
}
}
По умолчанию: false
Если установлено значение true, записи журнала содержат аргументы запроса под ключом uri_args.
Пример:```lua location / { access_by_lua_block { waf:set_option("event_log_request_arguments", true) } }
### event_log_request_body
*По умолчанию*: false
Если установлено значение true, записи журнала содержат тело запроса под ключом `request_body`.
*Пример*:```lua
location / {
access_by_lua_block {
waf:set_option("event_log_request_body", true)
}
}
По умолчанию: false
Заголовки HTTP-запроса копируются в событие журнала под ключом request_headers.
Пример:```lua location / { access_by_lua_block { waf:set_option("event_log_request_headers", true) } }
Результирующее событие содержит следующие дополнительные элементы:```json
{
"request_headers": {
"accept": "*/*",
"user-agent": "curl/7.22.0 (x86_64-pc-linux-gnu) libcurl/7.22.0 OpenSSL/1.0.1 zlib/1.2.3.4 libidn/1.23 librtmp/2.3"
}
}
По умолчанию: false
Включить SSL-соединения при ведении журнала через TCP/UDP.
Пример:```lua location / { access_by_lua_block { waf:set_option("event_log_ssl", true) } }
### event_log_ssl_sni_host
*По умолчанию*: none
Установите SNI-хост для подключений `lua-resty-logger-socket`.
*Пример*:```lua
location / {
access_by_lua_block {
waf:set_option("event_log_ssl_sni_host", "loghost.example.com")
}
}
По умолчанию: false
Включить проверку сертификатов для SSL-соединений при ведении журнала через TCP/UDP.
Пример:```lua location / { access_by_lua_block { waf:set_option("event_log_ssl_verify", true) } }
### event_log_socket_proto
*По умолчанию*: udp
Определяет, какой IP-протокол использовать (TCP или UDP) при отправке журналов событий через удалённый сокет. Независимо от протокола будет использоваться одинаковая логика буферизации и периодической записи.
*Пример*:```lua
location / {
access_by_lua_block {
-- send logs via TCP
waf:set_option("event_log_socket_proto", "tcp")
}
}
По умолчанию: error
Определяет назначение журналов событий. lua-resty-waf в настоящее время поддерживает запись в журнал ошибок, отдельный файл в локальной файловой системе или удалённый TCP- или UDP-сервер. В двух последних случаях журналы событий буферизуются и сбрасываются при достижении заданного порога (см. ниже дополнительные параметры, касающиеся ведения журналов событий).
Пример:```lua location / { access_by_lua_block { -- send event logs to the server's error_log location (default) waf:set_option("event_log_target", "error")
-- send event logs to a local file on disk
waf:set_option("event_log_target", "file")
-- send event logs to a remote server
waf:set_option("event_log_target", "socket")
}
}
Обратите внимание, что из-за ограничения используемой библиотеки ведения журналов можно определить только один целевой сокет. Иными словами, вы можете настроить только один целевой `socket` с определённой комбинацией хост/порт; если вы настроите вторую комбинацию хост/порт, данные не будут записываться должным образом.
### event_log_target_host
*По умолчанию*: не задано
Определяет целевой сервер для журналов событий, которые направляются на удалённый сервер.
*Пример*:```lua
location / {
access_by_lua_block {
waf:set_option("event_log_target_host", "10.10.10.10")
}
}
По умолчанию: нет
Определяет целевой путь для журналов событий, которые направляются в локальную файловую систему.
Пример:```lua location / { access_by_lua_block { waf:set_option("event_log_target_path", "/var/log/lua-resty-waf/event.log") } }
Этот путь должен находиться в месте, доступном для записи пользователем nginx. Обратите внимание, что по своей природе ведение журнала на диске может вызывать значительное снижение производительности в средах с высокой степенью параллелизма.
### event_log_target_port
*По умолчанию*: нет
Определяет целевой порт для журналов событий, отправляемых на удалённый сервер.
*Пример*:```lua
location / {
access_by_lua_block {
waf:set_option("event_log_target_port", 9001)
}
}
По умолчанию: нет
Переопределяет функциональность действий, выполняемых при срабатывании правила. Более подробно см. в примере.
Пример:```lua
location / {
access_by_lua_block {
local deny_override = function(waf, ctx)
ngx.log(ngx.INFO, "Overriding DENY action")
ngx.status = 404
end
-- override the DENY action with the function defined above
waf:set_option("hook_action", "DENY", deny_override)
}
}
### ignore_rule
*По умолчанию*: none
Инструктирует модуль игнорировать указанный идентификатор правила. Обратите внимание, что игнорирование правила в цепочке приведёт к игнорированию всей цепочки, и обработка продолжится со следующего правила после цепочки.
*Пример*:```lua
location / {
access_by_lua_block {
waf:set_option("ignore_rule", 40294)
waf:set_option("ignore_rule", {40002, 41036})
}
}
Multiple rules can be ignored by passing a table of rule IDs to set_option.
Default: none
Instructs the module to ignore an entire ruleset. This can be useful when some rulesets (such as the SQLi or XSS CRS rulesets) are too prone to false positives, or aren't applicable to your application.
Example:```lua location / { access_by_lua_block { waf:set_option("ignore_ruleset", "41000_sqli") } }
### mode
*По умолчанию*: SIMULATE
Задает режим работы модуля. Варианты: ACTIVE, INACTIVE и SIMULATE. В режиме ACTIVE совпадения с правилами регистрируются, а действия выполняются. В режиме SIMULATE lua-resty-waf проходит по каждому включенному правилу и регистрирует совпадения, но не выполняет действие, указанное для данного срабатывания. Режим INACTIVE предотвращает запуск модуля.
По умолчанию выбирается SIMULATE, если режим явно не задан; это требует, чтобы новые пользователи самостоятельно включали блокировку, устанавливая режим ACTIVE.
*Пример*:```lua
location / {
access_by_lua_block {
waf:set_option("mode", "ACTIVE")
}
}
Default: none
Задает DNS-резолвер(ы), используемые для RBL-запросов. В настоящее время поддерживается только трафик UDP/53. Этот параметр должен быть задан в виде числового адреса, а не имени хоста. Если этот параметр не задан, все правила RBL-проверки будут возвращать false.
Пример:```lua location / { access_by_lua_block { waf:set_option("nameservers", "10.10.10.10") } }
### process_multipart_body
*По умолчанию* true
Включите обработку тел запросов `multipart/form-data` (когда они присутствуют) с помощью модуля `lua-resty-upload`. В будущем lua-resty-waf может использовать эту обработку для более строгой проверки тел загрузок; пока этот модуль выполняет только минимальные проверки корректности тела запроса и не будет регистрировать событие, если тело запроса недействительно. Отключите эту опцию, если вам не нужна такая проверка или если ошибки в вышестоящем модуле вызывают проблемы с HTTP-загрузками.
*Пример*:```lua
location / {
access_by_lua_block {
-- disable processing of multipart/form-data requests
-- note that the request body will still be sent to the upstream
waf:set_option("process_multipart_body", false)
}
}
По умолчанию: false
Устанавливает HTTP-заголовок X-Lua-Resty-WAF-ID в upstream-запросе, значением которого является идентификатор транзакции. Этот идентификатор будет коррелировать с идентификатором транзакции, присутствующим в журналах отладки (если они включены). Это может быть полезно для отслеживания запросов или целей отладки.
Пример:```lua location / { access_by_lua_block { waf:set_option("req_tid_header", true) } }
### res_body_max_size
*По умолчанию*: 1048576 (1 МБ)
Определяет порог длины содержимого, при превышении которого тела ответов не будут обрабатываться. Этот размер тела ответа определяется заголовком ответа Content-Length. Если этого заголовка нет в ответе, тело ответа никогда не будет обработано.
*Пример*:```lua
location / {
access_by_lua_block {
-- increase the max response size to 2 MB
waf:set_option("res_body_max_size", 1024 * 1024 * 2)
}
}
Обратите внимание, что по своей природе требуется буферизовать всё тело ответа, чтобы правильно использовать ответ как коллекцию, поэтому значительно увеличивать это число не рекомендуется без обоснования (и достаточных ресурсов сервера).
По умолчанию: "text/plain", "text/html"
Определяет MIME-типы, с которыми lua-resty-waf будет обрабатывать тело ответа. Это значение определяется заголовком Content-Type. Если этого заголовка нет или тип ответа не входит в этот список, тело ответа обрабатываться не будет. Установка этого параметра добавит указанный MIME-тип к существующим значениям по умолчанию text/plain и text/html.
Пример:```lua location / { access_by_lua_block { -- mime types that will be processed are now text/plain, text/html, and text/json waf:set_option("res_body_mime_types", "text/json") } }
Несколько MIME-типов можно добавить, передав таблицу типов в `set_option`.
### res_tid_header
*По умолчанию*: false
Устанавливает HTTP-заголовок `X-Lua-Resty-WAF-ID` в нисходящем ответе, со значением идентификатора транзакции. Этот идентификатор будет коррелировать с идентификатором транзакции, присутствующим в журналах отладки (если задан). Это может быть полезно для отслеживания запросов или целей отладки.
*Пример*:```lua
location / {
access_by_lua_block {
waf:set_option("res_tid_header", true)
}
}
По умолчанию: 5
Задает порог для оценки аномалий. Когда порог достигнут, lua-resty-waf отклонит запрос.
Пример:```lua location / { access_by_lua_block { waf:set_option("score_threshold", 10) } }
### storage_backend
*По умолчанию*: dict
Определите механизм для постоянного хранения переменных. Доступные варианты: *dict* (разделяемая память ngx_lua), *memcached* и *redis*.
*Пример*:```lua
location / {
acccess_by_lua_block {
waf:set_option("storage_backend", "memcached")
}
}
По умолчанию: true
Включение или отключение TCP keepalive для соединений с удалёнными хостами постоянного хранилища.
Пример:```lua location / { acccess_by_lua_block { waf:set_option("storage_keepalive", false) } }
### storage_keepalive_timeout
*Default*: 10000
Настройте (в миллисекундах) тайм-аут для cosocket keepalive-пула для удаленных хостов постоянного хранилища.
*Пример*:```lua
location / {
acccess_by_lua_block {
waf:set_option("storage_keepalive_timeout", 30000)
}
}
По умолчанию: 100
Настройте размер пула cosocket keepalive для удалённых хостов постоянного хранения.
Пример:```lua location / { acccess_by_lua_block { waf:set_option("storage_keepalive_pool_size", 50) } }
### storage_memcached_host
*По умолчанию*: 127.0.0.1
Укажите хост, который будет использоваться при использовании memcached в качестве механизма хранения постоянных переменных.
*Пример*:```lua
location / {
acccess_by_lua_block {
waf:set_option("storage_memcached_host", "10.10.10.10")
}
}
По умолчанию: 11211
Определите порт для использования при использовании memcached в качестве механизма постоянного хранения переменных.
Пример:```lua location / { acccess_by_lua_block { waf:set_option("storage_memcached_port", 11221) } }
### storage_redis_host
*По умолчанию*: 127.0.0.1
Укажите хост для использования, когда redis применяется в качестве механизма постоянного хранения переменных.
*Пример*:```lua
location / {
acccess_by_lua_block {
waf:set_option("storage_redis_host", "10.10.10.10")
}
}
Default: 6379
Определите порт для использования при использовании redis в качестве механизма постоянного хранения переменных.
Пример:```lua location / { acccess_by_lua_block { waf:set_option("storage_redis_port", 6397) } }
### storage_zone
*По умолчанию*: none
Определяет `lua_shared_dict`, который будет использоваться для хранения данных постоянного хранилища. Эта зона должна быть определена в блоке `http{}` конфигурации.
*Пример*:_```lua
http {
-- define a 64M shared memory zone to hold persistent storage data
lua_shared_dict persistent_storage 64m;
}
location / {
access_by_lua_block {
waf:set_option("storage_zone", "persistent_storage")
}
}
Можно определить и использовать несколько общих зон, хотя в каждом месте конфигурации можно определить только одну зону. Если зона заполнена и интерфейс общего словаря не может добавить дополнительные ключи, в журнал ошибок будет записано следующее:
Error adding key to persistent storage, increase the size of the lua_shared_dict
lua-resty-waf предназначен для работы в нескольких фазах жизненного цикла запроса. Правила могут обрабатываться в следующих фазах:
Эти фазы соответствуют своим обработчикам Nginx lua (access_by_lua, header_filter_by_lua, body_filter_by_lua и log_by_lua соответственно). Обратите внимание, что запуск lua-resty-waf в обработчике фазы lua, отсутствующем в этом списке, приведёт к некорректной работе. Все данные, доступные на более ранней фазе, доступны и на более поздней фазе. То есть данные, доступные на фазе access, также доступны на фазах header_filter и body_filter, но не наоборот.
lua-resty-waf распространяется с рядом наборов правил, предназначенных для имитации функциональности ModSecurity CRS. Для справки эти наборы правил перечислены здесь:
lua-resty-waf разбирает определения правил из JSON-блобов, хранящихся на диске. Правила группируются по назначению и серьёзности и образуют набор правил. Включённые наборы правил были созданы для имитации некоторой функциональности ModSecurity CRS, особенно определений base_rules. Кроме того, включённый скрипт modsec2lua-resty-waf.pl можно использовать для преобразования дополнительных или пользовательских наборов правил в JSON-блоб, совместимый с lua-resty-waf.
Обратите внимание, что в скрипте преобразования есть несколько ограничений в отношении неподдерживаемых действий, коллекций и операторов. Актуальный список известных несовместимостей см. на этой странице вики.
Существует IRC-канал Freenode #lua-resty-waf. Travis CI отправляет сюда уведомления; не стесняйтесь также задавать вопросы и оставлять комментарии в этом канале.
Кроме того, вопросы и ответы доступны на CodeWake:
Направляйте все pull request'ы в ветку разработки или в функциональную ветку, если PR является значительным изменением. Коммиты в master должны поступать только в виде обновлений документации или других изменений, которые не влияют на сам модуль (и могут быть без конфликтов объединены с веткой разработки).
lua-resty-waf находится в процессе постоянной разработки и улучшения и, как следствие, может иметь ограничения в функциональности и производительности. Текущие известные ограничения можно найти в трекере проблем GitHub для этого репозитория.
Эта программа является свободным программным обеспечением: вы можете распространять и/или изменять её в соответствии с условиями Стандартной общественной лицензии GNU, опубликованной Фондом свободного программного обеспечения, либо версии 3 этой лицензии, либо (по вашему выбору) любой более поздней версии.
Эта программа распространяется в надежде, что она будет полезной, но БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ; без даже подразумеваемой гарантии КОММЕРЧЕСКОЙ ЦЕННОСТИ или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЁННОЙ ЦЕЛИ. Подробнее см. Стандартную общественную лицензию GNU.
Вы должны были получить копию Стандартной общественной лицензии GNU вместе с этой программой. Если вы её не получили, см. http://www.gnu.org/licenses/
Пожалуйста, сообщайте об ошибках, создавая тикет в трекере проблем GitHub.