INTEGRITY Документация

Функции

Cloudflare Rules language предоставляет функции для обработки и проверки значений в выражении:

Функции преобразования

Rules language поддерживает несколько функций для преобразования значений, извлечённых из HTTP-запросов. Типичным примером использования функций преобразования является приведение строки символов к верхнему или нижнему регистру, поскольку по умолчанию сравнение строк выполняется с учётом регистра.

Например, lower() функция преобразует все символы верхнего регистра в строке в нижний регистр.

В приведённом ниже выражении lower() функция преобразует http.host значения в нижний регистр, чтобы они соответствовали целевому значению "www.cloudflare.com":

lower(http.host) == "www.cloudflare.com"

Для функций преобразования, которые не принимают массивы в качестве типа аргумента, требуется [*] индексную запись. См. Массивы, где это описано подробнее.

Rules language поддерживает следующие функции преобразования:

any

any(Array<Boolean>): Boolean

Возвращает true когда оператор сравнения в аргументе возвращает true для any значений в массиве аргументов. Возвращает false в противном случае.

Пример:

any(url_decode(http.request.body.form.values[*])[*] contains "an xss attack")

all

all(Array<Boolean>): Boolean

Возвращает true когда оператор сравнения в аргументе возвращает true для all значений в массиве аргументов. Возвращает false в противном случае.

Пример:

all(http.request.headers["content-type"][*] == "application/json")

encode_base64

encode_base64(input String | Bytes [, flags String]): String

Кодирует input строку или массив байтов в формат Base64.

flags параметр необязателен. Можно указать один или несколько флагов в виде одной строки. Доступны следующие флаги:

По умолчанию результат кодируется в стандартном формате Base64 без дополнения (padding).

Примеры:

encode_base64("hello world")          will return "aGVsbG8gd29ybGQ"
encode_base64("hello world", "p")     will return "aGVsbG8gd29ybGQ="
encode_base64("hello world", "u")     will return "aGVsbG8gd29ybGQ"
encode_base64("hello world", "up")    will return "aGVsbG8gd29ybGQ="

Вы можете объединять encode_base64() с другими функциями, чтобы создавать подписанные заголовки запроса:

encode_base64(sha256(concat(to_string(ip.src), http.host, "my-secret")))

cidr

cidr(address IP address, ipv4_network_bits Integer, ipv6_network_bits Integer): IP address

Возвращает адрес сети, соответствующий IP-адресу (IPv4 или IPv6), с учётом указанных битов сети для IPv4 и IPv6 (которые определяют соответствующие маски подсети).

address параметр должен быть полем, то есть не может быть литералом String.

ipv4_network_bits значение должно быть от 1 до 32, а ipv6_network_bits значение должно быть от 1 до 128.

Примеры:

cidr6

cidr6(address IP address, ipv6_network_bits Integer): IP address

Возвращает адрес сети IPv6, соответствующий адресу IPv6, с учётом указанных битов сети (которые определяют маску подсети). Если в первом параметре вы укажете адрес IPv4, он будет возвращён без изменений.

address параметр должен быть полем, то есть не может быть литералом String.

ipv6_network_bits значение должно быть от 1 до 128.

Эта функция эквивалентна: cidr(<address>, 32, <ipv6_network_bits>).

Примеры:

concat

concat(String | Bytes | Array): String | Array

Принимает список значений, разделённых запятыми. Объединяет значения аргументов в один String или массив.

Тип возвращаемого значения зависит от типа входных аргументов. Например, при объединении массивов функция вернёт массив.

Например, concat("String1", " ", "String", "2") вернёт "String1 String2".

decode_base64

decode_base64(source String): String

Декодирует строку в кодировке Base64, указанную в source.

source должен быть полем, то есть не может быть литералом String.

Например, при следующем заголовке HTTP-запроса: client_id: MTIzYWJj, (any(decode_base64(http.request.headers["client_id"][*])[*] eq "123abc")) вернёт true.

ends_with

ends_with(source String, substring String): Boolean

Возвращает true когда источник заканчивается заданной подстрокой. Возвращает false в противном случае. Источником не может быть литеральное значение (например, "foo").

Например, если http.request.uri.path это "/welcome.html", затем ends_with(http.request.uri.path, ".html") вернёт true.

join

join(items Array<String>, separator String): String

Возвращает строку, полученную объединением строк в items на separator между элементами.

Если хотя бы один из аргументов равен nil, возвращаемое значение также будет nil.
Если items массив пуст, возвращаемое значение будет пустой строкой.
Если items массив содержит только один элемент, то объединение не производится и этот (единственный) элемент возвращается без изменений.

Эта функция выполняет действие, противоположное split() функцию.

Пример:

# Joins all HTTP request header names into a single string, with names separated by commas
join(http.request.headers.names, ",")

has_key

has_key(map: Map<T>, key: String): Boolean

Возвращает true, если key указанная во втором аргументе (это может быть литерал или динамическая строка), является существующим ключом в map указанному в первом аргументе; в противном случае возвращает false.

Тип данных значений в map (обозначается T) может быть любого типа.

Если хотя бы один из аргументов равен nil, возвращаемое значение также будет nil.

Примеры:

# Check if an HTTP request header exists:
has_key(http.request.headers, "x-my-header")

# Check if a request header exists based on the name of the first query argument:
has_key(http.request.headers, lower(http.request.uri.args.names[0]))

has_value

has_value(collection: Map<T> | Array<T>, value: T): Boolean

Возвращает true, если value указанное во втором аргументе (это может быть литерал или динамическое значение), найдено в collection указанному в первом аргументе; в противном случае возвращает false.

Тип данных значений в collection (обозначается T) должен соответствовать типу данных переданного value. Кроме того, T должен быть примитивным типом данных, то есть одним из следующих: Boolean, Integer, String, Bytes, или IP address.

Если хотя бы один из аргументов равен nil, возвращаемое значение также будет nil.

Примеры:

# Check if there is an HTTP request header with the exact name 'X-My-Header'
has_value(http.request.headers.names, "X-My-Header")

# Check if there is a request header with the exact name provided as the first query argument:
has_value(http.request.headers.names, http.request.uri.args.names[0])

is_jwt_present

is_jwt_present(token_configuration_id: String): Boolean

Возвращает true, если у запроса есть токен, настроенный в конфигурации токена с ID token_configuration_id.

token_configuration_id должен быть идентификатором существующего конфигурация токена.

Пример:

is_jwt_present("51231d16-01f1-48e3-93f8-91c99e81288e")

is_jwt_valid

is_jwt_valid(token_configuration_id: String): Boolean

Возвращает true, если у запроса есть действительный токен согласно конфигурации токена с ID token_configuration_id.

token_configuration_id должен быть идентификатором существующего конфигурация токена. Функция возвращает false, если токен отсутствует в запросе.

is_jwt_valid("51231d16-01f1-48e3-93f8-91c99e81288e")

len

len(String | Bytes | Array): Integer

Возвращает длину в байтах значения типа String или Bytes либо количество элементов в массиве.

Например, если значение http.host это "example.com", затем len(http.host) вернёт 11.

lookup_json_integer

lookup_json_integer(field String, key String | Integer, key String | Integer optional, ...): Integer

Возвращает целочисленное значение, связанное с указанным key в field.

field должен быть строковым представлением корректного JSON-документа.

key может быть именем атрибута, номером позиции (начиная с нуля) в массиве JSON или комбинацией этих двух вариантов (в виде дополнительных параметров функции), при этом путь строится по иерархии документа JSON, чтобы получить конкретное целочисленное значение.

Примечание: эта функция работает только с обычными целыми числами. Например, она не будет работать с числами с плавающей точкой, у которых дробная часть равна нулю, такими как 42.0.

Примеры:

lookup_json_string

lookup_json_string(field String, key String | Integer, key String | Integer optional, ...): String

Возвращает строковое значение, связанное с указанным key в field.

field должен быть строковым представлением корректного JSON-документа.

key может быть именем атрибута, номером позиции (начиная с нуля) в массиве JSON или комбинацией этих двух вариантов (в виде дополнительных параметров функции), при этом путь строится по иерархии документа JSON, чтобы получить конкретное значение.

Примеры:

lower

lower(String): String

Преобразует строковое поле в нижний регистр. Преобразуются только прописные байты ASCII. Остальные байты остаются без изменений.

Например, если http.host это "WWW.cloudflare.com", затем lower(http.host) == "www.cloudflare.com" вернёт true.

regex_replace

regex_replace(source String, regular_expression String, replacement String): String

Заменяет часть исходной строки, соответствующую регулярному выражению, строкой замены и возвращает результат. Строка замены может содержать ссылки на группы захвата регулярного выражения (например, ${1} и ${2}), до восьми ссылок на замену.

Примеры:

Создавайте группы захвата, заключая часть регулярного выражения в круглые скобки. Затем ссылайтесь на группу захвата с помощью ${<NUMBER>} в строке замены, где <NUMBER> это номер группы захвата.

Использовать можно только regex_replace() функцию только один раз в выражении, и её нельзя вкладывать в wildcard_replace() функцию.

remove_bytes

remove_bytes(Bytes): Bytes

Возвращает новый массив байтов, из которого удалены все вхождения заданных байтов.

Например, если http.host это "www.cloudflare.com", затем remove_bytes(http.host, "\x2e\x77") вернёт "cloudflarecom".

remove_query_args

remove_query_args(field String, query_param1 String, query_param2 String, ...): String

Удаляет один или несколько параметров строки запроса URI. Возвращает строку без указанных параметров.

field должен быть одним из следующих:

field не может быть литеральным значением, например "search=foo&order=asc".

remove_query_args() функция удалит все указанные параметры (в виде query_param1, query_param2, и т.д.) , включая повторяющиеся вхождения одного и того же параметра.

Порядок незатронутых параметров запроса сохраняется.

Примеры:

// If http.request.uri.query is "order=asc&country=GB":

remove_query_args(http.request.uri.query, "country")  will return "order=asc"
remove_query_args(http.request.uri.query, "order")    will return "country=GB"
remove_query_args(http.request.uri.query, "search")   will return "order=asc&country=GB" (unchanged)

// If http.request.uri.query is "category=Foo&order=desc&category=Bar":

remove_query_args(http.request.uri.query, "order")    will return "category=Foo&category=Bar"
remove_query_args(http.request.uri.query, "category") will return "order=desc"

sha256

sha256(input String | Bytes): Bytes

Вычисляет криптографический хэш SHA-256 для input строку или массив байтов. Возвращает хеш-значение длиной 32 байта.

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

Примеры:

sha256("my-token")

Приведённый выше пример возвращает 32-байтовый хеш, который ваш исходный сервер может проверить для аутентификации запросов.

Вы можете объединять sha256() с encode_base64() чтобы создавать подписи, закодированные в Base64:

encode_base64(sha256("my-token"))

Чтобы создать подписанное значение заголовка на основе атрибутов запроса:

encode_base64(sha256(concat(to_string(ip.src), to_string(http.request.timestamp.sec), "my-secret-key")))

split

split(input String, separator String, limit Integer): Array<String>

Разбивает input строку на массив строк, разбивая исходную строку в каждом месте, где встречается separator строку. Возвращаемый массив будет содержать не более limit количество элементов.

Если вы указываете limit значение меньше фактического количества подстрок в разбиваемой строке, последний элемент возвращаемого массива будет содержать остаток строки.

separator должен быть непустым строковым литералом.

limit является обязательным и должно быть целочисленным литералом от 1 до 128.

Если input равно nil, возвращаемое значение также будет nil.

Эта функция выполняет действие, противоположное join() функцию.

Примеры:

# Split a comma-separated list of categories obtained from an HTTP request header.

# A) Consider the following HTTP request header:
x-categories: groceries,electronics,diy,auto

split(http.request.headers["x-categories"][0], ",", 64)  will return ["groceries", "electronics", "diy", "auto"]
split(http.request.headers["x-categories"][0], ",", 3)   will return ["groceries", "electronics", "diy,auto"]

# B) Consider the following HTTP request header:
x-categories: groceries,,electronics

split(http.request.headers["x-categories"][0], ",", 64)  will return ["groceries", "", "electronics"]

starts_with

starts_with(source String, substring String): Boolean

Возвращает true когда источник начинается с заданной подстроки. Возвращает false в противном случае. Источником не может быть литеральное значение (например, "foo").

Например, если http.request.uri.path это "/blog/first-post", затем starts_with(http.request.uri.path, "/blog") вернёт true.

substring

substring(field String | Bytes, start Integer, end Integer optional): String

Возвращает часть field значение (значение типа String или Bytes поле) из start индекса байта до (но не включая) end индекса байта. Первый байт в field имеет индекс 0. Если не указать необязательный end индекс, функция возвращает часть строки начиная с start индекса и до конца строки.

start и end индексы могут быть отрицательными целыми числами, что позволяет обращаться к символам с конца строки, а не с начала.

Примеры:

// If http.request.body.raw is "asdfghjk":

substring(http.request.body.raw, 2, 5)   will return "dfg"
substring(http.request.body.raw, 2)      will return "dfghjk"
substring(http.request.body.raw, -2)     will return "jk"
substring(http.request.body.raw, 0, -2)  will return "asdfgh"

to_string

to_string(Integer | Boolean | IP address): String

Возвращает строковое представление значения типа Integer, Boolean или IP-адрес.

Примеры:

// If cf.bot_management.score is 5:
to_string(cf.bot_management.score)   will return "5"

// If ssl is true:
to_string(ssl)                       will return "true"

upper

upper(String): String

Преобразует строковое поле в верхний регистр. Преобразуются только строчные байты ASCII. Остальные байты остаются без изменений.

Например, если http.host является"www.cloudflare.com", затем upper(http.host) вернёт "WWW.CLOUDFLARE.COM".

url_decode

url_decode(source String, options String optional): String

Декодирует строку в формате URL, заданную в source, как показано ниже:

source должен быть полем, то есть не может быть строковым литералом.

options параметр необязателен. Все параметры нужно указывать в виде одной строки в кавычках, например "r" или "ur". Доступны следующие варианты:

Примеры:

url_decode("John%20Doe")   will return "John Doe"
url_decode("John+Doe")     will return "John Doe"
url_decode("%2520")        will return "%20"
url_decode("%2520", "r")   will return " "

// Using url_decode() with the any() function:
any(url_decode(http.request.body.form.values[*])[*] contains "an xss attack")

// Using the u option to match a specific alphabet
url_decode(http.request.uri.path) matches "(?u)\p{Hangul}+"

uuidv4

uuidv4(source Bytes): String

Генерирует случайный UUIDv4 (Universally Unique Identifier, версия 4) на основе переданного аргумента (источника случайности). Чтобы получить массив случайных байтов, используйте cf.random_seed поле.

Например, uuidv4(cf.random_seed) вернёт UUIDv4, похожий на 49887398-6bcf-485f-8899-f15dbef4d1d5.

wildcard_replace

wildcard_replace(source Bytes, wildcard_pattern Bytes, replacement Bytes, flags Bytes optional): String

Заменяет source строку, соответствующую литералу с нулём или более * подстановочные метасимволы на строку замены и возвращает результат. Строка замены может содержать ссылки на группы захвата подстановочных знаков (например, ${1} и ${2}), до восьми ссылок на замену.

Если совпадений нет, функция вернёт source без изменений.

source параметр должен быть полем (он не может быть литеральной строкой). Кроме того, весь source значение должно соответствовать wildcard_pattern параметр (он не может совпадать только с частью значения поля).

Чтобы ввести литерал * символ в wildcard_pattern параметр, его нужно экранировать с помощью \*. Кроме того, необходимо также экранировать \ с помощью \\. Два неэкранированных * символов подряд (**) в этом параметре считаются недопустимыми и не могут использоваться. Если необходимо экранирование символов, рекомендуется использовать синтаксис необработанных строк для wildcard_pattern параметр.

Чтобы ввести литерал $ символ в replacement параметр, его нужно экранировать с помощью $$.

Чтобы выполнить сопоставление с подстановочными знаками с учетом регистра, задайте flags параметр в "s".

Эта функция использует ленивое сопоставление, то есть пытается сопоставить каждый * метасимвол с максимально короткой строкой.

Использовать можно только wildcard_replace() функцию только один раз в выражении, и её нельзя вкладывать в regex_replace() функцию.

Примеры:

Дополнительные примеры сопоставления с подстановочными знаками см. в Сопоставление с подстановочными знаками.

Cloudflare Network Firewall Functions

bit_slice

bit_slice(protocol String, offset_start Number, offset_end Number): Number

Эта функция ищет совпадения в заданном срезе битов.

Смещение отсчитывается от указанного заголовка протокола. Например, чтобы проверить первый бит полезной нагрузки пакета UDP, нужно задать offset_start к 64.

Это в первую очередь предназначено для использования с ip, udp, а также tcp.

Срез (offset_end, offset_start) не может превышать 32 бита, но несколько вызовов можно объединить с помощью логических выражений.

bit_slice смещение не может превышать 2,040 бит.

Проверка HMAC

Обзор

Вы можете проверять токены с кодом аутентификации сообщений на основе хеш-функции (HMAC) в выражении правила с помощью is_timed_hmac_valid_v0() функция, сигнатура которой выглядит так:

is_timed_hmac_valid_v0(
  <String literal as Key>,
  <String field as MessageMAC>,
  <Integer literal as ttl>,
  <Integer as currentTimeStamp>,
  <Optional Integer literal as lengthOfSeparator, default: 0>,
  <Optional String literal as flags>
) -> <Bool as result>

is_timed_hmac_valid_v0() функция имеет следующие определения параметров:

Использование

is_timed_hmac_valid_v0() функция использует переданный Ключ чтобы сгенерировать код аутентификации сообщения (MAC) на основе message и timestamp областей MessageMAC. Если сгенерированный MAC совпадает с mac области MessageMAC и срок действия токена не истёк, HMAC считается действительным, и функция возвращает true.

Например, следующее выражение соответствует запросам к downloads.example.com которые не содержат действительных токенов HMAC:

http.host == "downloads.example.com"
and not is_timed_hmac_valid_v0("mysecretkey", http.request.uri, 100000, http.request.timestamp.sec, 8)

Примеры правил с проверкой HMAC см. в Настройка аутентификации по токену в документации WAF.

MessageMAC

Корректный MessageMAC соответствует следующему регулярному выражению:

(.+)(.*)(\d{10})-(.{43,})

и состоит из следующих выражений, разделённых скобками:

Выражение Описание Пример
(.+) message для проверки. /download/cat.jpg
(.*) separator между сообщением и меткой времени, обычно это имя параметра. &verify=
(\d{10}) 10-значный UNIX timestamp когда был выпущен MAC, в секундах. 1484063137
(.{43,}) Версия в кодировке Base64 mac. Если не задать значение urlSafe аргумент в функции проверки HMAC на 's', необходимо выполнить URL-кодирование значения Base64 для mac. Если кодирование MAC в Base64 является URL-safe, mac значение содержит 43 байта. В противном случае значение будет состоять из 44 и более байт из-за URL-кодирования. IaLGSmELTvlhfd0ItdN6PhhHTFhzx73EX8uy%2FcSDiIU%3D

Сведения о генерации MessageMAC см. в Генерация HMAC-токена.

Примеры проверки HMAC

MessageMAC в одном поле

Рассмотрим случай, когда MessageMAC полностью содержится в одном поле, как в этом примере пути URI:

/download/cat.jpg?verify=1484063787-IaLGSmELTvlhfd0ItdN6PhhHTFhzx73EX8uy%2FcSDiIU%3D

Обратите внимание, как URI соотносится с элементами MessageMAC:

Элемент Значение
message /download/cat.jpg
separator ?verify= (длиной 8)
timestamp 1484063787
mac IaLGSmELTvlhfd0ItdN6PhhHTFhzx73EX8uy%2FcSDiIU%3D

Если MessageMAC полностью содержится в одном поле, например http.request.uri, передайте имя поля в MessageMAC аргумент функции проверки HMAC:

is_timed_hmac_valid_v0(
  "mysecretkey",
  http.request.uri,
  100000,
  http.request.timestamp.sec,
  8
)

Аргумент MessageMAC в виде конкатенации

Чтобы составить MessageMAC из нескольких полей, используйте concat() функцию.

В этом примере формируется значение MessageMAC аргумент путем объединения URI запроса и двух полей заголовков:

is_timed_hmac_valid_v0(
  "mysecretkey",
  concat(
    http.request.uri,
    http.request.headers["timestamp"][0],
    "-",
    http.request.headers["mac"][0]),
  100000,
  http.request.timestamp.sec,
  0
)