UserGate Policy Language (UPL)
 
UserGate Policy Language (Описание)

UPL (UserGate Policy Language) — язык описания политик UserGate. Термин "политика" употребляется здесь в контексте конфигурации правил, применяемых для принятия решений по требованиям аутентификации, правам доступа или преобразования контента.

Правила настраиваются с использованием действий, условий и свойств.

Для каждого правила настраивается одно из действий. Действия — настройки, которые управляют обработкой транзакции (OK, WARNING, PASS, DENY, FORCE_PASS, FORCE_DENY). При настройке правил, в которых не предусмотрено указание действия (например, правила DNS, NAT и маршрутизации, пропускной способности и т.п.), необходимо указать действия PASS или OK.

Условия задаются знаками равно (=) или не равно (!=), например, зоны, адреса, GeoIP источников и назначения, сервисы, приложения и т.д.; все условия в правиле проверяются по логическому И, т.е. правило сработает, если будут выполнены все условия.

Свойства правил задаются в круглых скобках и используются для указания дополнительной информации, например, название правил, их описание, функция журналирования и т.д.

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

UPL используется для создания правил в персональных слоях WAF. Также с помощью UPL в интерфейсе CLI создаются правила политик сети для следующих разделов:

  • Межсетевой экрана (уровень: network-policy firewall).

  • Правила reverse-прокси (уровень: global-portal reverse-proxy-rules).

Структура команды для создания правила:

Admin@nodename# create <level> <position> upl-rule <str-upl-syntax>

где <level> — уровень, на котором необходимо создать правило.

      <position> — позиция, на которую будет помещено правило.

      <str-upl-syntax> строка, в которой описано правило в UPL синтаксисе.

Структура команды для обновления существующего правила:

Admin@nodename# set <level> <position> upl-rule <str-upl-syntax>

где <level> — уровень, на котором необходимо обновить правило.

      <position> — номер правила, которое необходимо обновить.

      <str-upl-syntax> строка, в которой описано правило в UPL синтаксисе.

Структура команды для удаления правила:

Admin@nodename# delete <level> <position | all>

где <level> — уровень, на котором необходимо удалить правило.

      <position> — номер правила, которое необходимо удалить.

      <all> — удалить все правила.

Структура команды для отображения правила:

Admin@nodename# show <level> <position | all>

где <level> — раздел, правила которого нужно отобразить.

      <position> — номер правила, которое необходимо отобразить.

      <all> — отобразить все правила.

Пример создания правила межсетевого экрана с использованием UPL (использован многострочный ввод):

Admin@nodename# create network-policy firewall 1 upl-rule \
...DENY \
...src.zone = Trusted \
...dst.zone = Untrusted \
...user = known \
...time = lib.time("Working hours") \
...rule_log(session)\
...name("Example of firewall rule created in CLI") \
...enabled(true)

После создания правило отобразиться в начале списка правил межсетевого экрана (на позиции 1). Данное правило запрещает HTTPS-трафик из зоны Trusted в зону Untrusted пользователям, идентифицированным системой. Правило работает в соответствии с расписанием "Working hours". При срабатывании правила в журнал будет записана информация о начале сессии.

В последующих статьях данного раздела можно найти более подробную информацию об общих положениях языка UPL, определениях, встроенных библиотеках, условиях, действиях, свойствах и типах правил

   

Общие положения

Комментарии

Любая строка, начинающаяся с символа "%", является комментарием.
Символ процента "%" после пробела или табуляции вводит комментарий, который продолжается до конца строки (кроме случаев, когда символ процента отображается внутри кавычек (""), как часть выражения).

Пример

% Это комментарий
DENY("Too many Host headers") request.header.Host.count = 2..  % и это тоже

Комментарии могут быть в любом месте файла с описанием политик.

Правила

Правило политики (rule) состоит из условий и некоторого количества действий, записанных в любом порядке. Есть также свойства (properties), которые синтаксически выглядят как действие, но при этом активных действий не производят. Например, свойство name просто добавляет атрибут "имя" в правило.

Правила обычно пишутся в одной строке, но могут быть разбиты на строки с помощью специального символа — обратного слеша "\".

Когда правило выполняется, условие проверяется для текущей конкретной транзакции. Если условие оценивается как True (истина), выполняются все перечисленные действия и текущий слой заканчивается при наличии префиксов PASS / FORCE_PASS / DENY / FORCE_DENY / WARNING / OK. Ecли сработавшее правило не имеет префиксов PASS / FORCE_PASS / DENY / FORCE_DENY / WARNING / OK, то выполняются действия и дальше обрабатывается уже следующее правило. Если условие оценивается как False для этой транзакции, то дальше обрабатывается уже следующее правило.

Все условия в правиле проверяются по логическому "И". Другими словами, правило сработает, когда будут выполнены все условия.

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

Действия — это настройки, которые управляют обработкой транзакции. Например, запретить (deny) или обработать объект (изменить заголовок — rewrite).

Синтаксис:

Rule ::= (PASS | FORCE_PASS | DENY| ( DENY '(' string ')') | FORCE_DENY | FORCE_DENY'(' string ') '| WARNING | OK)? Conditions '\'? Actions

Conditions ::= condition '\'? Conditions

Actions ::= action '\'? Actions

Пример:

Запрос будет запрещен, когда сработают оба триггера:

  • домен будет example.com

  • время будет между 9 и 17 часами

DENY url.domain = "example.com" time=09:00..17:00

Слои

Слой (layer)— это конструкция UPL, используемая для группировки правил и принятия одного решения. Раздельные принятия решения помогают контролировать сложность политики. Это делается путем написания каждого решения в отдельном слое.

У любого правила в слое может быть префикс PASS / FORCE_PASS / DENY / FORCE_DENY / OK / WARNING, когда срабатывает правило с таким префиксом, все остальные правила в слое пропускаются.

В случае если сработало правило с префиксом FORCE_PASS или FORCE_DENY, то это является окончательным результатом обработки, в противном случае обработка переходит на следующий слой. После обработки всех слоев запрос будет заблокирован или пропущен в зависимости от того, что было последним — PASS / FORCE_PASS или DENY / FORCE_DENY. Если процессинг остановится на WARNING, будет добавлено предупреждение в тело ответа.

Префикс OK подразумевает остановку обработки правил в текущем слое при выполнении условий и действий (если таковые указаны). Если префикс отсутствует при выполнении условий и действий, то остановка не подразумевается.

Действия FORCE_PASS и FORCE_DENY похожи на PASS и DENY, за исключением того, что они могут быть переопределены на последующих слоях. FORCE_DENY и FORCE_PASS немедленно прекращают поверку правил как на текущем, так и на последующих слоях, и этот результат является окончательным.

Синтаксис:

Layer ::= '[' layer_type layer_name ']'

layer_type ::= firewall | reverseproxy | reverseproxy_balancing

layer_name ::= string

atom ::= [a-z][0-9a-zA-Z_]+

string ::= '"' произвольная строка '"'

Пример 1:

[content "L1"]
DENY enabled(true) % по умолчанию все запрещено
 
[content "Devs"]
DENY group != Developers enabled(true)
%... дальше идут правила, которые будут применяться только для группы Developers

Пример 2:

[content "Admin"]
FORCE_PASS group = Admins enabled(true)
  
[content "L2"]
DENY enabled(true) % по умолчанию все запрещено 

Динамические значения

Значения "адрес запроса" (url, url.host, url.path), "IP-адрес источника/назначения" (src.ip, dst.ip), "значения заголовков" (request и response) и "параметры запроса" (qparam) могут сравниваться между собой, а также использоваться в качестве аргумента в действиях (actions), где это предусмотрено.

Условия

Условие (condition) в языке UPL является логической комбинацией триггеров. Триггеры — это отдельные тесты, которые можно выполнить с компонентами запроса, ответа, связанными пользователями или состоянием системы. Все триггеры условия сравниваются со значениями с помощью операторов "=" и "!=". В роли значения могут выступать константные значения, такие как строки, целочисленные значения, диапазоны значений, динамические значения.

Синтаксис:

condition ::= condition_name   ('=' | '!=')  condition_value

condition_value ::= pattern | list

list ::= '(' ((pattern ',')* pattern)? ')'

pattern ::= word | string | integer | float | boolean| range | condition_name

string ::= '"' произвольная строка '"'

word ::= [a-zA-Z][0-9a-zA-Z_\-]*

boolean ::= yes|no|true|false

range ::= integer .. [integer] | [integer] .. integer | float .. [float] | [float] .. float

numeric :: = integer | range

http.method

Проверка используемого HTTP-метода. Метод можно указывать как в кавычках, так и без.

Синтаксис:

http.method =   GET | CONNECT | DELETE | HEAD | POST | PUT | TRACE | OPTIONS | TUNNEL | LINK | UNLINK | PATCH | PROPFIND | PROPPATCH | MKCOL | COPY | MOVE | LOCK | UNLOCK | MKDIR | INDEX | RMDIR | COPY | MOVE

http.request.version

Проверка версии HTTP-запроса.

Синтаксис:

http.request.version = 0.9 | 1.0 | 1.1

http.response.version

Проверка версии HTTP-ответа.

Синтаксис:

http.response.version = 0.9 | 1.0 | 1.1

http.response.code

Проверка HTTP-кода ответа. Валидные значения: 100 - 999.

Синтаксис:

http.response.code = NNN  %(где NNN число от 100 до 999)

http.request.body, http.request.body.nocase, http.response.body и http.response.body.nocase

Проверка тела запроса/ответа HTTP на содержание определенной сигнатуры.

Пример:

DENY http.response.body.nocase = "<title>index of" http.response.body = ">"

request.header.<h_name> и response.header.<h_name>

Проверка HTTP-заголовка запроса/ответа. h_name может принимать одно из поддерживаемых значений (смотрите список поддерживаемых HTTP-заголовков в Приложении).

Синтаксис:

request.header.<h_name>[.base64][.nocase] = string

Пример:

DENY url="http://usergate.com" request.header.Pragma="no-cache"
 
PASS request.header.User-Agent = lib.useragent("Browsers")
PASS request.header.Content-Type = lib.mime("Applications")
DENY request.header.Connection.substring = "Upgrade"

request.header.<h_name>.substring и response.header.<h_name>.substring

Проверка HTTP-заголовка запроса/ответа на вхождение подстроки. h_name может принимать одно из поддерживаемых значений (смотрите список поддерживаемых HTTP-заголовков в Приложении).

Синтаксис:

request.header.<h_name>[.base64]substring[.nocase] = string

Пример:

DENY request.header.User-Agent.substring = "curl/"

request.header.<h_name>.regex и response.header.<h_name>.regex

Проверка HTTP-заголовка запроса/ответа на регулярное выражение PCRE. h_name может принимать одно из поддерживаемых значений (смотрите список поддерживаемых HTTP-заголовков в Приложении).

Синтаксис:

request.header.<h_name>[.base64].regex = string

Пример:

DENY("Accept only digits in content length") request.header.Content-Length.regex != "[0-9]*"

request.header.<h_name>.re2 и response.header.<h_name>.re2

Проверка HTTP-заголовка запроса/ответа на регулярное выражение RE2. h_name может принимать одно из поддерживаемых значений (смотрите список поддерживаемых HTTP-заголовков в Приложении).

Синтаксис:

request.header.<h_name>[.base64].re2 = string

Пример:

DENY("Accept only digits in content length") request.header.Content-Length.re3 != "[0-9]*"

request.header.<h_name>.count и response.header.<h_name>.count

Проверка количества заголовков <h_name> в HTTP-запросе/ответе. h_name может принимать одно из поддерживаемых значений (смотрите список поддерживаемых HTTP-заголовков в Приложении).

Синтаксис:

request.header.<h_name>.count = integer | range

Пример:

DENY("Too many Host headers") request.header.Host.count = 2..

request.header.<h_name>.length и response.header.<h_name>.length

Проверка длины значений всех заголовков <h_name> в HTTP-запросе/ответе. h_name может принимать одно из поддерживаемых значений (смотрите список поддерживаемых HTTP-заголовков в Приложении).

Синтаксис:

request.header.<h_name>.length = integer | range

Пример:

DENY("Too much Cookie data") request.header.Cookie.length = 2048..

request.header_names, request.header_values, response.header_names и response.header_values

Проверка имени/значения всех HTTP-заголовков запроса/ответа на значение.

Синтаксис:

request.header_values[.base64].regex = string

request.header_values[.base64].re2 = string

request.header_values[.base64].substring[.nocase] = string

request.header_values.count = integer | range

request.header_values.length = integer | range

request.x_header.<xh_name> и response.x_header.<xh_name>

Проверка HTTP-заголовка запроса/ответа на значение. xh_name — произвольный HTTP-заголовок.

Синтаксис:

request.x_header.<xh_name>[.base64][.nocase] = string

request.x_header.<xh_name>[.base64].regex = string

request.x_header.<xh_name>[.base64].re2 = string

request.x_header.<xh_name>[.base64].substring[.nocase] = string

request.x_header.<xh_name>.count = integer | range

request.x_header.<xh_name>.length = integer | range

Пример:

DENY url="http://usergate.com" request.x_header.Test="test1"

Возможны также суффиксы lengthcountregexre2 как и в случае с <h_name>.

DENY("Too much X-Test data") request.x_header.X-Test.length = 2048..
DENY("Too much X-Test2 headers data") request.x_header.X-Test2.count = 2..
PASS request.x_header.Test.regex = "[0-9]*"

request.header.Cookie.<cookie_name>

Проверка заголовка запроса Cookie на значение.

Синтаксис:

request.header.Cookie.<cookie_name>[.base64][.(nocase | substring | substring.nocase | regex | re2)] = string

Пример:

DENY http.method = POST request.header.Cookie.csrf_token != qparam.CSRF_TOKEN enabled(true) name("Check CSRF")

time, day, hour, minute

Проверка соответствия текущего времени заданному условию. Если не указан суффикс utc, время берется локальное, иначе — по Гринвичу.

Синтаксис:

day[.utc] = monday | tuesday | wednesday | thursday | friday | saturday | sunday | DD | list

time[.utc] = HH:MM | range | lib.time(<name>)

hour[.utc] = HH | range

minute[.utc] = MM | range

HH ::= 00 - 23

MM ::= 00 - 59

DD ::= 1 - 31

Пример:

PASS time = 12:00..13:00  % разрешить каждый день с 12 до 13 часов
PASS time = lib.time("Праздники") % использовать библиотеку "Праздники"
DENY day = (sunday, saturday) % запретить на выходных
DENY day = (monday, 15) hour = 9..18  % запретить каждый понедельник и каждое 15 число месяца с 9 до 18 часов

Открытые интервалы учитываются по границе суток/часа.


PASS hour = 18.. % означает, что разрешено с 18 часов до полуночи
minute = ..10 % первые 10 минут каждого часа

url, url.host и url.address

Проверка url или его части на значение. Проверка использует нормализованный URI c декодированными *%*.

Синтаксис:

url[.(prefix | substring | suffix | regex | re2)] = string

url.host[.(prefix | substring | suffix | regex | re2)] = string

url.domain[.(prefix | substring | suffix | regex | re2)] = string

url.address = ip_address | subnet | subnet_label

url.port = [low_port]..[high_port] | port

url.path[.base64][.(prefix | substring | suffix | regex | re2)] = string

url.is_absolute = yes | no     % полный или нет URL

prefix ::= string              % начало строки

substring ::= string           % подстрока

suffix ::= string              % окончание строки

regex ::= string               % регулярное выражение PCRE

re2 ::= string                 % регулярное выражение RE2

url.address — это, по сути, синоним dst.ip.

Пример:

DENY url.path.base64.re2 = "(?i)\bondisconnecting\W*=" enabled(true) name("ondisconnecting (URI)")

qparam.<name>, qparam.values и qparam.names

Проверка значения параметров запроса. Проверка использует имена и значения параметров c декодированными *%*.

Синтаксис:

qparam.length = numeric          % проверить общую длину query-параметров

qparam.count = numeric           % проверить количество query-параметров qparam.<name>[.(length | count)] = numeric

qparam.<name>[.base64][.(nocase | substring | substring.nocase | regex | re2)] = string

qparam.values[.base64].substring[.nocase] = string % проверить все значения на вхождение подстроки

qparam.names[.base64].substring[.nocase] = string  % проверить все имена на вхождение подстроки

qparam.values[.base64].regex = string              % проверить все значения на регулярное выражение

qparam.names[.base64].regex = string               % проверить все имена на регулярные выражения

qparam.values[.base64].re2 = string                % проверить все значения на регулярное выражение

qparam.names[.base64].re2 = string                 % проверить все имена на регулярные выражения numeric ::= integer | range      % число либо диапазон

regex ::= string                 % регулярное выражение PCRE

re2 ::= string                   % регулярное выражение RE2

Пример:

DENY("limit arguments total length") qparam.length = 1024..                 % total
DENY("Limit argument value length") qparam.values.length = 1024..           % for each
DENY("Limit argument name length") qparam.names.length = 1024..             % for each
DENY("Maximum number of arguments in request limited") qparam.count  = 12.. % total
DENY("PHP injection attempt") qparam.values.base64.substring.nocase = "${@print"

src и dst

Проверка условия на IP-адрес, зону или GeoIP источника/назначения. 

Синтаксис:

src.ip = ip_address | subnet | subnet_label | list | lib

dst.ip = ip_address | subnet | subnet_label | list | lib

src.zone = integer | zone_name

dst.zone = integer | zone_name

src.geoip = iso3166 | list

dst.geoip = iso3166 | list

src.mac = mac_address | list

dst.mac = mac_address | list

lib ::= lib.(network | url) '(' list_libs ')'

list_libs :: = lib_name ','' list_libs

lib_name ::= word | string

iso3166 ::= [A-Z][A-Z]

url.address — это, по сути, синоним dst.ip.

response_time

Проверка времени ответа в миллисекундах.

Синтаксис:

response_time = integer

Встроенные библиотеки

Библиотеки (lib) — это элементы языка UPL, которые служат для доступа к встроенным и пользовательским библиотекам. Как правило, это достаточно большие списки, которые неудобно описывать через определения def. Обращение к библиотекам происходит по их именам.

Синтаксис:

library ::= lib.<url | useragent | network | time>(list_names)

list_names ::= name list_names

name ::= word | string

url — список URL;
useragent — список юзерагентов;
network — список сетей/IP-адресов;
time — библиотека с промежутками времени.

Пример:

DENY src.ip = lib.network("Bad ips", "Test ips")
DENY dst.ip = lib.network("Bad ips")
DENY dst.ip = lib.url("Bad urls") % в данном случае домены будут резолвиться в ip-адреса
 
PASS request.header.User-Agent = lib.useragent("Browsers")
DENY time = lib.time(Weekends)

Определения

В файлах политик определения (def) служат для объединения наборов условий или действий. Каждое определение должно иметь уникальное пользовательское имя, по которому к нему можно обратиться из правил.

def condition

Наборы условий. Все условия в одной строке проверяются по логическому И. Перевод строки означает логическое ИЛИ. Символ экранирования — обратный слэш ("\") в конце строки позволяет перенести условие по И на следующую строку.

Синтаксис:

def condition label_name

    conditions

end

conditions ::= condition '\'? [conditions]

condition ::= name '=' value

label_name ::= atom

atom ::= [a-z][0-9a-zA-Z_]+

def var

Определение переменных. Служит для подсчета некоторых событий за определенный интервал времени. Для изменения значения предназначены действия inc и dec.

Синтаксис:

def var label_name

    init ::= integer

    window ::= time

    key ::= condition_name | condition_list

end

label_name ::= atom

atom ::= [a-z][0-9a-zA-Z_]+

condition_list ::= '(' condition_name , condition_list ')'

init — это начальное значение переменной, к которому она вернется по истечении времени window;

key — поле или список полей, по которым группируются значения переменной (необязательный параметр).

Свойства

Свойства (properties) — это некие атрибуты правила, например, name или enabled. Они используются для предоставления дополнительной информации в процессе обработки правил. Синтаксис свойств точно такой же, как у действий.

Синтаксис:

property = prop_name | prop_name '(' list_params ')'

prop_name ::= name | desc | id | rule_log | enabled

list_params ::= value ',' list_params

name и desc

Атрибуты имя и описание для правила.

Синтаксис:

Name ::= name '(' string|word ')'

Description ::= desc '(' string ')'

Пример:

DENY hour = 9..18 category = News name("Запретить News")  desc("Запретить категорию News в рабочее время")

enabled

Атрибут, который включает или выключает работу правила.

Синтаксис:

Enable ::= enabled '(' boolean ')'

boolean ::= yes | no | true | false       % (по умолчанию false)

rule_log

Устанавливает атрибут журналирования правила. Значение session действительно только для правил межсетевого экрана, защиты от dos-атак и пропускной способности.

Синтаксис:

Logging ::= rule_log '(' boolean | session ')'

LoggingFwRule ::= rule_log '(' boolean , interval,  burst')'

boolean ::= yes | no | true | false         % (по умолчанию no)

interval ::= "integer/[s,m,h,d]"

burst ::= integer

interval — среднее число пакетов, попадающих под условие limit в единицу времени (1/s, 1/m, 1/h, 1/d) , default = 3/h;
burst — максимальное число пакетов, попадающих в под условие limit за один раз (default = 5).

profile

Устанавливает профиль правила.

Синтаксис:

Profile ::= profile '(' string | word | list ')'

certificate

Сертификат, используемый для поддержки HTTPS-соединения. Действительно только для правил reverse-прокси.

Синтаксис:

CertAuthEnabled ::= cert_auth_enabled '(' boolean ')'

Certificate ::= certificate '(' certificate_name ')'

certificate_name ::= string | word

gateway

Шлюз. Имя одного из существующих шлюзов. Действительно только для правил NAT и маршрутизации, и для условий сценария "Проверка состояния".

Синтаксис:

Gateway ::= gateway '(' string | word ')'

Свойства правил межсетевого экрана

reject_with

Устанавливает способ, с помощью которого будет блокироваться трафик. Действительно только для правил межсетевого экрана.

Синтаксис:

Reject ::= reject_with '(' "tcp-reset-both" | "tcp-rst" | "host-unreach" ')'

fragmented

Проверка на фрагментированность пакетов. Действительно только для правил межсетевого экрана.

Синтаксис:

Fragmented ::= fragmented '(' boolean ')'

boolean ::= yes | no | true | false

yes — проверяются только фрагментированные пакеты;
no — проверяются только нефрагментированные пакеты;
—, если свойство fragmented не указано, то будут проверяться все пакеты.

block_invalid_cert

Блокирование сайтов с некорректными сертификатами. Действительно только для правил инспектирования SSL.

Синтаксис:

InvalidCertificate ::= block_invalid_cert '(' boolean ')'

boolean ::= yes | no | true | false

check_revoc_cert

Проверка по списку отозванных сертификатов. Действительно только для правил инспектирования SSL.

Синтаксис:

ChekRevocation ::= check_revoc_cert '(' boolean ')'

boolean ::= yes | no | true | false

block_expired_cert

Блокировка сертификатов с истекшим сроком действия. Действительно только для правил инспектирования SSL.

Синтаксис:

ExpiredCertificate ::= block_expired_cert '(' boolean ')'

boolean ::= yes | no | true | false

block_self_signed_cert

Блокировка самоподписанных сертификатов. Действительно только для правил инспектирования SSL.

Синтаксис:

SelfSignedCertificate ::= block_self_signed_cert '(' boolean ')'

boolean ::= yes | no | true | false

ssl_profile

Профиль SSL. Действительно только для правил инспектирования SSL, reverse-прокси, веб-портала.

Синтаксис:

SslProfile ::= ssl_profile '(' string | word ')'

Свойства правил reverse-прокси

is_https

Включение поддержки HTTPS. Действительно только для правил Reverse-прокси.

Синтаксис:

IsHttps ::= is_https '(' boolean ')'

boolean ::= yes | no | true | false

rewrite_path

Подмена путей. Действительно только для правил Reverse-прокси.

Синтаксис:

RewritePath ::= rewrite_path '(' path_from, path_to ')'

path_from — изменить с (домен и/или путь URL, которые требуется изменить);
path_to — изменить на (домен и/или путь URL, на которые требуется заменить старые).

waf_profile

Профиль WAF. Действительно только для правил Reverse-прокси.

Синтаксис:

WafProfile ::= waf_profile '(' string | word | list ')'

Действия

Действие (action) — это то, что будет выполнено, если условия в правиле истинны. В качестве параметров могут использоваться константные значения, или динамические значение там, где это предусмотрено.

Синтаксис:

action = action_name | action_name '(' list_params ')'

action_name ::= log_message | append | delete | set | replace | encrypt | inc|dec | reset | redirect | encrypt_body_url | decrypt_path | body_inject | set_cookie_token | body_replace | lookup_and_auth | encode_cookie | decode_cookie | sma | action_label

action_label ::= 'action'.<action_label_name>

action_label_name ::= atom

list_params ::= value ',' list_params

log_message

Записать сообщения в журнал.

Пример:

DENY category = lib.category(Productivity) log_message("Deny porno")

append

Добавить заголовок к HTTP-запросу/ответу. Список поддерживаемых заголовков приведен в Приложении.

Первый параметр может быть опущен, если заголовок относится к одной группе request или response.

Синтаксис:

append([request | response,] <headername>, value)

headername — см. в Приложении.
value ::= string | numeric | condition_name.

set

Переписать значение конкретному HTTP-заголовку. Список поддерживаемых заголовков см. в Приложении.
Первый параметр может быть опущен, если заголовок относится к одной группе request или response.

Синтаксис:

set([request | response,] <headername>, value)

headername — см. в Приложении.
value ::= string | numeric | condition_name.

delete

Удалить HTT- заголовок. Список поддерживаемых заголовков см. в Приложении.

Первый параметр может быть опущен, если заголовок относится к одной группе request или response.

Синтаксис:

delete([request | response,] <headername>)

headername — см. в Приложении.

replace

Модифицировать значение HTTP-заголовка. Список поддерживаемых заголовков см. в Приложении.

Первый параметр может быть опущен, если заголовок относится к одной группе request или response.

Синтаксис:

replace([request | response,] <headername>, regex, value)

regex ::= string               % регулярное выражение

value ::= string | condition_name

headername — см. в Приложении.

Пример 1:

Добавить заголовок Referer:

PASS append(Referer, "http://example.com") enabled(true)

Удалить заголовок:

PASS delete(Referer)

Переписать заголовок:

PASS set(request, Cache-Control, no-cache)

Модифицировать заголовок Location:

PASS response.header.Location.count = 1.. replace(response, Location, "http://example.com", url.host) enabled(true)

Пример 2:

define action delete_referer
    log_message("Referer header deleted")
    delete(request, Referer)
end

encrypt

Шифровать часть пути в HTTP-заголовке. Список поддерживаемых заголовков см. в Приложении.
Первый параметр может быть опущен, если заголовок относится к одной группе request или response.
Ключ шифрования и флаг "Использовать IP как часть ключа шифрования" — необязательные параметры.

Синтаксис:

encrypt([request | response,] <headername>, <url>[, <user_key>[, <add_ip>]])

url ::= string               % часть url для фильтрации

user_key ::= string          % пользовательский ключ шифрования (необязательный параметр)

add_ip ::= boolean           % добавлять ли IP к ключу шифрования (логическое значение, необязательный параметр)

boolean ::= yes | no | true | false

headername — см. в Приложении.

encrypt_body_url

Шифровать часть пути в ссылках тела ответа.
Ключ шифрования и флаг "Использовать IP как часть ключа шифрования"  — необязательные параметры.

Синтаксис:

encrypt_body_url(<url>[, <user_key>[, <add_ip>]])

url ::= string               % часть url для фильтрации

user_key ::= string          % пользовательский ключ шифрования (необязательный параметр)

add_ip ::= boolean           % добавлять ли IP к ключу шифрования (логическое значение, необязательный параметр)

boolean ::= yes | no | true | false

decrypt_path

Дешифровать часть пути запроса.

Первый параметр может быть опущен, если заголовок относится к одной группе request или response.

Ключ шифрования и флаг "Использовать IP как часть ключа шифрования"  — необязательные параметры.

Синтаксис:

decrypt_path(<path>[, <user_key>[, <add_ip>]])

path ::= string              % часть пути для фильтрации

user_key ::= string          % пользовательский ключ шифрования (необязательный параметр)

add_ip ::= boolean           % добавлять ли IP к ключу шифрования (логическое значение, необязательный параметр)

boolean ::= yes | no | true | false

Пример:

Шифровать все относительные пути в заголовке Location и теле ответа, и дешифровать путь запроса:

decrypt_path("/", "User_Key", true) enabled(true) name("Path decode")
http.response.code = 302 encrypt(Location, "/", "User_Key", true) enabled(true) name("Encrypt Location header")
encrypt_body_url("/", "User_Key", true) enabled(true) name("Encrypt all relative URL")

body_inject

Вставить скрипт в тело ответа.

Синтаксис:

body_inject(inject_text)

inject_text ::= string

set_cookie_token

Добавить в ответ заголовок 'Set-Cookie' со сгенерированным токеном.

Синтаксис:

set_cookie_token(cookie_name, parameter, expires_date)

cookie_name ::= string

parameter ::= string

expires_date ::= [DD_]HH:MM   % время которое будет прибавлено к текущему времени

Пример:

Реализация CSRF защиты:

DENY http.method = POST request.header.Referer.substring = "/login.php" qparam.UCSRF_TOKEN != request.header.Cookie.ucsrf_token enabled(true) name("Check CSRF")
url.path.prefix = "/login.php" set_cookie_token(ucsrf_token, "path=/", 01_00:00) body_inject("<script language='JavaScript'>
    var tokenName = 'UCSRF_TOKEN';
  
    document.addEventListener('DOMContentLoaded', function()
    {
        var t_res = document.cookie.match(/ucsrf_token=(.+?)(;|$)/);
        var tokenValue = t_res ? t_res[1] : '';
  
        var forms = document.getElementsByTagName('form');
        for(i=0; i<forms.length; i++)
        {
            var html = forms[i].innerHTML;
            html += '<input type=hidden name=' + tokenName + ' value=' + tokenValue + ' />';
            forms[i].innerHTML = html;
        }
    });
</script>") enabled(true) name("Inject")

encode_cookie

Шифровать значения Cookie в заголовке Set-Cookie с заданным именем.

Синтаксис:

encode_cookie(cookie_name[, condition_name][, user_kry_string][, f_encrypt])

cookie_name ::= string

condition_name                    % условие используемое для кодирования (по умолчанию src.ip)

user_kry_string ::= string        % пользовательский ключ шифрования (по умолчанию "")

f_encrypt := true                 % необходимо шифрование  (по умолчанию false)

decode_cookie

Дешифровать токен в заголовке Cookie с заданным именем.

Синтаксис:

decode_cookie(cookie_name[, condition_key][, user_kry_string][, f_decript])

cookie_name ::= string

condition_name                    % условие используемое для декодирования (по умолчанию src.ip)

user_kry_string ::= string        % пользовательский ключ шифрования (по умолчанию "")

f_encrypt := true                 % необходимо шифрование  (по умолчанию false)

Пример:

Шифрование и дешифрование Cookie с именем security:

response.header.Set-Cookie.count != 0 encode_cookie("security", src.ip, true) enabled(true) name("encode_cookie")
request.header.Cookie.count != 0 decode_cookie("security", src.ip, true) enabled(true) name("decode_cookie")

body_replace

Модифицировать тело ответа. Выполняется не более двух (первых) модификаций для каждого ответа.

Синтаксис:

body_replace(<regex>, <value>)

regex ::= string               % регулярное выражение

value ::= string

Пример:

PASS \
body_replace("(\\+7|8)[\\s(]?(\\d\{3})[\\s)]?(\\d\{3})[\\s-]?(\\d\{2})[\\s-]?(\\d\{2})", "+\\1 (\\2) \\3-XX-XX") \
body_replace("(\\w{1})[\\w\.]*(\\w{1})@([\\w]+)\\.([\\w]+)", "\\1***\\2@\\3.\\4") \
enabled(true) \
name("Replace mail and phone")

lookup_and_auth

Аутентифицировать пользователя. В случае если IP не указан, запрос маркируется имением пользователя.

Синтаксис:

lookup_and_auth(<user_login>[, <ip_address>[, <session_timeout>]])

user_login ::= string | condition_name    % Логин аутентификации

ip_address ::= string | condition_name    % IP адрес 

session_timeout ::= integer               % тайм-аут сессии, по умолчанию 0.

Пример:

lookup_and_auth(request.x_header.X-Authenticated-User, request.x_header.X-Forwarded-For, 300) enabled(true) name("User authentication")
lookup_and_auth(request.x_header.X-Authenticated-User) enabled(true) name("Mark request")

redirect

При блокировке перенаправить пользователя на адрес, который указан в редиректе.

Синтаксис:

Redirect ::= redirect(RespCode[, RedirectText], Url)

RespCode ::= 301 | 302 | 305 | 307

RedirectText ::= string

Url ::= string

Пример:

DENY src.zone = Trusted redirect(302, "Custom test (Moved)", "https://block.captive/block")
DENY src.zone = Untrusted redirect(302, "https://block.captive/block")

inc и dec

Используются для изменения значения переменных, объявленных как def var.

Синтаксис:

inc(var.<var_name>, integer)

dec(var.<var_name>, integer)

Пример:

На каждый http.response.code = 500 увеличивается значение rps на 1. Если превысили 10 таких запросов за 5 минут, блокируем дальнейшие ответы. Через 5 минут переменная rps будет сброшена в 0:

def var rps
    init = 0
    window = 00:05
    key = src.ip
end
 
http.response.code = 500 var.rps=..10 inc(var.rps, 1) enabled(true)
 
PASS var.rps = 5 log_message("Warning!") enabled(true)
 
DENY var.rps=11.. log_message("Too many 500 errors!") enabled(true)

reset

Сбросить значения переменных, объявленных как init в def var, в начальное значение.

Синтаксис:

reset(var.<var_name>)

sma

Используются для подсчета среднего значения в окне времени, которое определяется в переменной как window в def var.

Синтаксис:

sma(var.<var_name>, integer)

Пример:

Блокируются запросы, когда среднее время запроса за 30-секундный интервал превысит 2 секунды:

def var avg_time
    init = 0
    window = 00:00:30
    key = src.ip
end
 
src.zone = Untrusted sma(var.avg_time, response_time) enabled(true) name("sma")
DENY src.zone = Untrusted var.avg_time = 2000.. enabled(true) name("sma res")  

Типы правил

Правила межсетевого экрана

Префиксы

Имя

Описание

PASS

Разрешение трафика.

DENY

Блокировка трафика.

Условия

src.zonesrc.geoipsrc.ip.

dst.zonedst.geoipdst.ip.

timeurl.

Свойства

namedescenabledrule_logreject_with.

Пример

[firewall "Firewall rules"]
% ----------------- 1 -----------------
DENY \
    scenario = "Example torrent detection scenario" \
    dst.zone = Untrusted \
    dst.ip = lib.network("Botnets IP list") \
    rule_log(session) \
    reject_with("host-unreach") \
    enabled(true) \
    name("Example block RU RKN by IP list")
% ----------------- 2 -----------------
PASS \
    scenario = "Example torrent detection scenario" \
    src.zone = Trusted \
    dst.zone = Untrusted \
    rule_log(yes, "3/h", 5) \
    enabled(true) \
    name("Allow trusted to untrusted")

Правила защиты почтового трафика

Префиксы

Имя

Описание

PASS

Пропуск трафика без изменений.

DENY ("with error")

Блокировка письма, при этом сообщается об ошибке доставки письма на сервер.

DENY

Блокировка письма без уведомления о блокировке.

WARNING

Маркировка почтовых сообщений.

Условия

src.zonesrc.geoipsrc.ip.

dst.zonedst.geoipdst.ip.

userservice, envelope_from, envelope_to.

Свойства

namedescenabledrule_logmark_hdrmarkantispam_usergatednsbl.

Пример

[mailsecurity "Mail Security Rules"]
% ----------------- 1 -----------------
PASS \
    user = (example, "CN=VPN users,DC=LOCAL") \
    envelope_from = "Email froup from" \
    envelope_to = "Email froup to" \
    service = SMTP \
    rule_log(yes) \
    mark_hdr(Subject) \
    enabled(true) \
    name("Mail Pass Rule")
% ----------------- 2 -----------------
DENY("with error") \
    service = (SMTPS, SMTP) \
    rule_log(yes) \
    mark_hdr(Subject) \
    antispam_usergate(yes) \
    enabled(true) \
    name("Mail Drop Rule")
% ----------------- 3 -----------------
DENY \
    src.zone = Untrusted \
    service = SMTP \
    mark_hdr(Subject) \
    dnsbl(yes) \
    enabled(false) \
    name("DNSBL spam drop rule")
% ----------------- 4 -----------------
WARNING \
    src.zone = Untrusted \
    service = (SMTP, POP3, SMTPS, POP3S) \
    mark_hdr(Subject) \
    mark("[SPAM]") \
    antispam_usergate(yes) \
    enabled(false) \
    name("SMTP and POP3 filtering")

Правила reverse-прокси

Префиксы

Имя

Описание

OK

Всегда ОК.

Условия

src.zonesrc.geoipsrc.ipsrc.mac.

dst.zonedst.geoipdst.ip.

request.header.User-Agenturl.port.

Свойства

namedescenabledrule_logprofile, certificateis_httpsssl_profile

waf_profilerewrite_path.

Пример

[reverseproxy "Reverse proxy Rules"]
% ----------------- 1 -----------------
OK \
    url.port = 80 \
    src.zone = Untrusted \
    desc("Example reverse proxy rule. This is an example rule which can be changed or deleted if necessary. ") \
    profile("Example reverse proxy server") \
    rewrite_path("example.com/path1", "example.local/path1") \
    waf_profile("Example WAF profile") \
    enabled(true) \
    name("Example reverse proxy rule")

Правила балансировки reverse-прокси

Префиксы

Имя

Описание

OK

Всегда ОК.

Свойства

namedescenabled, profile.

Пример

[reverseproxy_balancing "Reverse proxy load balancing Rules"]
% ----------------- 1 -----------------
OK \
    profile("Example reverse proxy server") \
    enabled(true) \
    name("Reverse-proxy load balancing")

Правила временной блокировки IP-адреса

Префиксы

Имя

Описание

DENY

Блокировка IP-адреса

Условия

http.response.code

Свойства

nameenabled

Пример

В примере для конкретного источника (условие scr.ip) настроен подсчет количества кодов ответа 404. Если количество таких ответов за последние 30 секунд превысит 10, IP-адрес этого источника будет заблокирован на одну минуту.

def var counter_404
    init = 0
    window = 00:00:30   
    key = src.ip
end
def var block
    init = 0
    window = 00:01:00
    key = src.ip
end
 
DENY var.block = 1.. log_message("Black list") enabled(true) name("Black list")
http.response.code = 404 inc(var.counter_404, 1) log_message("Incriment counter")  enabled(true) name("Incriment counter")
DENY var.counter_404 = 10.. inc(var.block, 1) log_message("Enable block") enabled(true) name("Enable block")

Список поддерживаемых HTTP-заголовков

HTTP Header

Request/Response

SET/REPLACE/ENCRYPT

APPEND

DELETE

Accept

Request

(отметить)

(отметить)

(отметить)

Accept-Charset

Request

(отметить)

(отметить)

(отметить)

Accept-Encoding

Request

(отметить)

(отметить)

(отметить)

Accept-Language

Request

(отметить)

(отметить)

(отметить)

Accept-Ranges

Response

(отметить)

(отметить)

(отметить)

Age

Response

Allow

Request/Response

(отметить)

(отметить)

(отметить)

Authorization

Request

Cache-Control

Request/Response

(отметить)

(отметить)

(отметить)

Client-IP

Request

(отметить)

(отметить)

Connection

Request/Response

(отметить)

Content-Encoding

Request/Response

(отметить)

Content-Language

Request/Response

(отметить)

Content-Length

Request/Response

Content-Location

Request/Response

(отметить)

(отметить)

Content-Range

Request/Response

Content-Type

Request/Response

Cookie

Request

(отметить)

(отметить)

(отметить)

Date

Request/Response

ETag

Response

(отметить)

(отметить)

Expect

Request

(отметить)

Expires

Request/Response

(отметить)

(отметить)

From

Request

(отметить)

(отметить)

Host

Request

If-Match

Request

(отметить)

If-Modified-Since

Request

If-None-Match

Request

(отметить)

If-Range

Request

If-Unmodified-Since

Request

Last-Modified

Request/Response

Location

Response

(отметить)

(отметить)

Max-Forwards

Request

Meter

Request/Response

(отметить)

(отметить)

Pragma

Request/Response

(отметить)

(отметить)

Proxy-Authenticate

Response

(отметить)

Proxy-Authorization

Request

(отметить)

Proxy-Connection

Request

(отметить)

Range

Request

(отметить)

(отметить)

Referer

Request

(отметить)

(отметить)

Retry-After

Response

(отметить)

(отметить)

Server

Response

(отметить)

(отметить)

Set-Cookie

Response

(отметить)

(отметить)

(отметить)

TE

Request

(отметить)

Trailer

Request/Response

(отметить)

Transfer-Encoding

Request/Response

(отметить)

Upgrade

Request/Response

(отметить)

User-Agent

Request

(отметить)

(отметить)

Vary

Response

(отметить)

(отметить)

(отметить)

Via

Request/Response

(отметить)

(отметить)

(отметить)

Warning

Request/Response

(отметить)

(отметить)

(отметить)

WWW-Authenticate

Response