The Cloudflare Rules language provides functions for manipulating and validating values in an expression:
The Rules language supports several functions that transform values extracted from HTTP requests. A common use case for transformation functions is the conversion of a string of characters to uppercase or lowercase, since by default, string evaluation is case-sensitive.
For example, the lower()
function converts all uppercase characters in a string to lowercase.
In the expression below, the lower()
function transforms http.host
values to lowercase so that they match the target value "www.cloudflare.com"
:
lower(http.host) == "www.cloudflare.com"
Transformation functions that do not take arrays as an argument type require the [*]
index notation. Refer to Arrays for more information.
The Rules language supports these transformation functions:
any(Array<Boolean>)
: Boolean
Returns true
when the comparison operator in the argument returns true
for any of the values in the argument array. Returns false
otherwise.
Example:
any(url_decode(http.request.body.form.values[*])[*] contains "an xss attack")
all(Array<Boolean>)
: Boolean
Returns true
when the comparison operator in the argument returns true
for all values in the argument array. Returns false
otherwise.
Example:
all(http.request.headers["content-type"][*] == "application/json")
cidr(address IP address, ipv4_network_bits Integer, ipv6_network_bits Integer)
: IP address
Returns the network address corresponding to an IP address (IPv4 or IPv6), given the provided IPv4 and IPv6 network bits (which determine the corresponding netmasks).
The address
parameter must be a field, that is, it cannot be a literal String.
The ipv4_network_bits
value must be between 1 and 32, and the ipv6_network_bits
value must be between 1 and 128.
Examples:
ip.src
is 113.10.0.2
, cidr(ip.src, 24, 24)
will return 113.10.0.0
.ip.src
is 2001:0000:130F:0000:0000:09C0:876A:130B
, cidr(ip.src, 24, 24)
will return 2001:0000:0000:0000:0000:0000:0000:0000
.Warning
You can only use the cidr()
function in custom rules and rate limiting rules.
cidr6(address IP address, ipv6_network_bits Integer)
: IP address
Returns the IPv6 network address corresponding to an IPv6 address, given the provided network bits (which determine the netmask). If you provide an IPv4 address in the first parameter, it will be returned unchanged.
The address
parameter must be a field, that is, it cannot be a literal String.
The ipv6_network_bits
value must be between 1 and 128.
This function is equivalent to: cidr(<address>, 32, <ipv6_network_bits>)
.
Examples:
ip.src
is 2001:0000:130F:0000:0000:09C0:876A:130B
, cidr6(ip.src, 24)
will return 2001:0000:0000:0000:0000:0000:0000:0000
.ip.src
is 113.10.0.2
, cidr6(ip.src, 24)
will return 113.10.0.2
(unchanged).Warning
You can only use the cidr6()
function in custom rules and rate limiting rules.
concat(String | Bytes | Array)
: String | Array
Takes a comma-separated list of values. Concatenates the argument values into a single String or array.
The return type depends on the type of input arguments. For example, if you concatenate arrays, the function will return an array.
For example, concat("String1", " ", "String", "2")
will return "String1 String2"
.
decode_base64(source String)
: String
Decodes a Base64-encoded String specified in source
.
source
must be a field, that is, it cannot be a literal String.
For example, with the following HTTP request header: client_id: MTIzYWJj
, (any(decode_base64(http.request.headers["client_id"][*])[*] eq "123abc"))
would return true
.
Warning
You can only use the decode_base64()
function in header transform rules, custom rules, and rate limiting rules.
ends_with(source String, substring String)
: Boolean
Returns true
when the source ends with a given substring. Returns false
otherwise. The source cannot be a literal value (like "foo"
).
For example, if http.request.uri.path
is "/welcome.html"
, then ends_with(http.request.uri.path, ".html")
will return true
.
len(String | Bytes | Array)
: Integer
Returns the byte length of a String or Bytes value, or the number of elements in an array.
For example, if the value of http.host
is "example.com"
, then len(http.host)
will return 11
.
lookup_json_integer(field String, key String | Integer, key String | Integer optional, ...)
: Integer
Returns the integer value associated with the supplied key
in field
.
The field
must be a string representation of a valid JSON document.
The key
can be an attribute name, a zero-based position number in a JSON array, or a combination of these two options (as extra function parameters), while following the hierarchy of the JSON document to obtain a specific integer value.
Note: This function only works for plain integers. For example, it will not work for floating numbers with a zero decimal part such as 42.0
.
Examples:
Given the following JSON object contained in the http.request.body.raw
field:{ "record_id": "aed53a", "version": 2 }
Then lookup_json_integer(http.request.body.raw, "version")
will return 2
.
Given the following nested object:{ "product": { "id": 356 } }
Then lookup_json_integer(http.request.body.raw, "product", "id")
will return 356
.
Given the following JSON array at the root level:["first_item", -234]
Then lookup_json_integer(http.request.body.raw, 1)
will return -234
.
Given the following array in a JSON object attribute:{ "network_ids": [123, 456] }
Then lookup_json_integer(http.request.body.raw, "network_ids", 0)
will return 123
.
Given the following root-level array of JSON objects:[{ "product_id": 123 }, { "product_id": 456 }]
Then lookup_json_integer(http.request.body.raw, 1, "product_id")
will return 456
.
lookup_json_string(field String, key String | Integer, key String | Integer optional, ...)
: String
Returns the string value associated with the supplied key
in field
.
The field
must be a string representation of a valid JSON document.
The key
can be an attribute name, a zero-based position number in a JSON array, or a combination of these two options (as extra function parameters), while following the hierarchy of the JSON document to obtain a specific value.
Examples:
Given the following JSON object contained in the http.request.body.raw
field:{ "company": "cloudflare", "product": "rulesets" }
Then lookup_json_string(http.request.body.raw, "company") == "cloudflare"
will return true
.
Given the following nested object:{ "network": { "name": "cloudflare" } }
Then lookup_json_string(http.request.body.raw, "network", "name") == "cloudflare"
will return true
.
Given the following JSON array at the root level:["other_company", "cloudflare"]
Then lookup_json_string(http.request.body.raw, 1) == "cloudflare"
will return true
.
Given the following array in a JSON object attribute:{ "networks": ["other_company", "cloudflare"] }
Then lookup_json_string(http.request.body.raw, "networks", 1) == "cloudflare"
will return true
.
Given the following root-level array of JSON objects:[{ "network": "other_company" }, { "network": "cloudflare" }]
Then lookup_json_string(http.request.body.raw, 1, "network") == "cloudflare"
will return true
.
lower(String)
: String
Converts a string field to lowercase. Only uppercase ASCII bytes are converted. All other bytes are unaffected.
For example, if http.host
is "WWW.cloudflare.com"
, then lower(http.host) == "www.cloudflare.com"
will return true
.
regex_replace(source String, regular_expression String, replacement String)
: String
Replaces a part of a source string matched by a regular expression with a replacement string, returning the result. The replacement string can contain references to regular expression capture groups (for example, ${1}
and ${2}
), up to eight replacement references.
Examples:
Literal match replace:regex_replace("/foo/bar", "/bar$", "/baz") == "/foo/baz"
If there is no match, the input string does not change:regex_replace("/x", "^/y$", "/mumble") == "/x"
Match is case-sensitive by default:regex_replace("/foo", "^/FOO$", "/x") == "/foo"
When there are multiple matches, only one replacement occurs (the first one):regex_replace("/a/a", "/a", "/b") == "/b/a"
Escape a $
in the replacement string by prefixing it with another $
:regex_replace("/b", "^/b$", "/b$$") == "/b$"
Replace with capture groups:regex_replace("/foo/a/path", "^/foo/([^/]*)/(.*)$", "/bar/${2}/${1}") == "/bar/path/a/"
Create capture groups by putting part of the regular expression in parentheses. Then, reference a capture group using ${<NUMBER>}
in the replacement string, where <NUMBER>
is the number of the capture group.
Warning
You can only use the regex_replace()
function in rewrite expressions of Transform Rules and target URL expressions of dynamic URL redirects.
remove_bytes(Bytes)
: Bytes
Returns a new byte array with all the occurrences of the given bytes removed.
For example, if http.host
is "www.cloudflare.com"
, then remove_bytes(http.host, "\x2e\x77")
will return "cloudflarecom"
.
starts_with(source String, substring String)
: Boolean
Returns true
when the source starts with a given substring. Returns false
otherwise. The source cannot be a literal value (like "foo"
).
For example, if http.request.uri.path
is "/blog/first-post"
, then starts_with(http.request.uri.path, "/blog")
will return true
.
substring(field String | Bytes, start Integer, end Integer optional)
: String
Returns part of the field
value (the value of a String or Bytes field) from the start
byte index up to (but excluding) the end
byte index. The first byte in field
has index 0
. If you do not provide the optional end
index, the function returns the part of the string from start
index to the end of the string.
The start
and end
indexes can be negative integer values, which allows you to access characters from the end of the string instead of the beginning.
Examples:
// 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(Integer | Boolean | IP address)
: String
Returns the string representation of an Integer, Boolean, or IP address value.
Examples:
// 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"
Warning
You can only use the to_string()
function in rewrite expressions of Transform Rules and target URL expressions of dynamic URL redirects.
upper(String)
: String
Converts a string field to uppercase. Only lowercase ASCII bytes are converted. All other bytes are unaffected.
For example, if http.host
is"www.cloudflare.com"
, then upper(http.host)
will return "WWW.CLOUDFLARE.COM"
.
url_decode(source String, options String optional)
: String
Decodes a URL-formatted string defined in source
, as in the following:
%20
and +
decode to a space character (
).
%E4%BD
decodes to ä½
.
The source
must be a field, that is, it cannot be a literal string.
The options
parameter is optional. You must provide any options as a single string wrapped in quotes, such as "r"
or "ur"
. The available options are the following:
r
: Applies recursive decoding. For example, %2520
will be decoded twice (recursively) to a space character (
).u
: Enables Unicode percent decoding. The result will be encoded in UTF-8. For example, "%u2601"
would be decoded to a cloud emoji (âï¸
) encoded in UTF-8 ("\xe2\x98\x81"
, with a size of 3 bytes).Examples:
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(source Bytes)
: String
Generates a random UUIDv4 (Universally Unique Identifier, version 4) based on the given argument (a source of randomness). To obtain an array of random bytes, use the cf.random_seed
field.
For example, uuidv4(cf.random_seed)
will return a UUIDv4 similar to 49887398-6bcf-485f-8899-f15dbef4d1d5
.
Warning
You can only use the uuidv4()
function in rewrite expressions of Transform Rules.
wildcard_replace(source Bytes, wildcard_pattern Bytes, replacement Bytes, flags Bytes optional)
: String
Replaces a source
string, matched by a literal with zero or more *
wildcard metacharacters, with a replacement string, returning the result. The replacement string can contain references to wildcard capture groups (for example, ${1}
and ${2}
), up to eight replacement references.
If there is no match, the function will return source
unchanged.
The source
parameter must be a field (it cannot be a literal string). Additionally, the entire source
value must match the wildcard_pattern
parameter (it cannot match only part of the field value).
To enter a literal *
character in the wildcard_pattern
parameter, you must escape it using \*
. Additionally, you must also escape \
using \\
. Two unescaped *
characters in a row (**
) in this parameter are considered invalid and cannot be used. If you need to perform character escaping, it is recommended that you use the raw string syntax for the wildcard_pattern
parameter.
To enter a literal $
character in the replacement
parameter, you must escape it using $$
.
To perform case-sensitive wildcard matching, set the flags
parameter to "s"
.
This function uses lazy matching, that is, it tries to match each *
metacharacter with the shortest possible string.
Examples:
If the full URI is https://apps.example.com/calendar/admin?expand=true
,wildcard_replace(http.request.full_uri, "https://*.example.com/*/*", "https://example.com/${1}/${2}/${3}")
will return https://example.com/apps/calendar/admin?expand=true
If the full URI is https://example.com/applications/app1
,wildcard_replace(http.request.full_uri, "/applications/*", "/apps/${1}")
will return https://example.com/applications/app1
(unchanged value, since there is no match for the full URI value; you should use the http.request.uri.path
field for URI path matching).
If the URI path is /calendar
,wildcard_replace(http.request.uri.path, "/*", "/apps/${1}")
will return /apps/calendar
.
If the URI path is /Apps/calendar
,wildcard_replace(http.request.uri.path, "/apps/*", "/${1}")
will return /calendar
(case-insensitive match by default).
If the URI path is /Apps/calendar
,wildcard_replace(http.request.uri.path, "/apps/*", "/${1}", "s")
will return /Apps/calendar
(unchanged value) because there is no case-sensitive match.
If the URI path is /apps/calendar/login
,wildcard_replace(http.request.uri.path, "/apps/*/login", "/${1}/login")
will return /calendar/login
.
For more examples of wildcard matching, refer to Wildcard matching.
Warning
Currently, you can only use the wildcard_replace()
function in rewrite expressions of URL rewrites and target URL expressions of dynamic URL redirects.
bit_slice(protocol String, offset_start Number, offset_end Number)
: Number
This function looks for matches on a given slice of bits.
The offset starts on the given protocol header. For example, to match on the first bit of payload for a UDP packet, you must set offset_start
to 64
.
This is primarily intended for use with ip
, udp
, and tcp
.
The slice (offset_end
â offset_start
) cannot be longer than 32 bits, but multiple calls can be joined together by using logical expressions.
The bit_slice
offset cannot exceed 2,040 bits.
Note
Access to the HMAC validation function requires a Cloudflare Pro, Business, or Enterprise plan.
You can validate hash-based message authentication code (HMAC) tokens in a rule expression by using the is_timed_hmac_valid_v0()
function, which has this signature:
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>
The is_timed_hmac_valid_v0()
function has these parameter definitions:
Key
String literal
MessageMAC
String
message
, separator
, timestamp
, mac
. For a definition and an example, refer to MessageMAC.ttl
Integer literal
currentTimeStamp
Integer
http.request.timestamp.sec
field as an approximate value to this argument.lengthOfSeparator
Integer literal optional
separator
between the timestamp
and the message
in the MessageMAC
. Expressed in bytes, with a default value of 0
.flags
String literal optional
When you set this optional argument to 's'
, the function expects the value of the Base64-encoded mac
in the MessageMAC
argument to use the URL-safe character set with no padding.
When you do not set the value of flags
to 's'
, you must URL encode the Base64 value for mac
in the MessageMAC
argument.
The is_timed_hmac_valid_v0()
function uses the supplied Key to generate a message authentication code (MAC) from the message
and the timestamp
regions of the MessageMAC. When the generated MAC matches the mac
region of the MessageMAC and the token has not expired, the HMAC is valid and the function returns true
.
For example, the following expression matches requests to downloads.example.com
that do not include valid HMAC tokens:
http.host == "downloads.example.com"
and not is_timed_hmac_valid_v0("mysecretkey", http.request.uri, 100000, http.request.timestamp.sec, 8)
For examples of rules that use HMAC validation, refer to Configure token authentication in the WAF documentation.
A valid MessageMAC satisfies the following regular expression:
(.+)(.*)(\d{10})-(.{43,})
and is composed of these parentheses-delimited expressions:
Expression Description Example(.+)
The message
to validate. /download/cat.jpg
(.*)
The separator
between message and timestamp, commonly a parameter name. &verify=
(\d{10})
The 10-digit UNIX timestamp
when the MAC was issued, expressed in seconds. 1484063137
(.{43,})
A Base64-encoded version of the mac
. When you do not set the value of the urlSafe
argument in the HMAC validation function to 's'
, you must URL-encode the Base64 value for mac
. When the Base64 MAC encoding is URL-safe, the mac
value contains 43 bytes. Otherwise, the value will be 44 bytes or more, because of URL encoding. IaLGSmELTvlhfd0ItdN6PhhHTFhzx73EX8uy%2FcSDiIU%3D
For details on generating a MessageMAC, refer to HMAC token generation.
Important
When you do not use the optional flags
argument for is_timed_hmac_valid_v0()
, you must URL-encode the Base64 value for mac
in the MessageMAC
argument.
For more information, refer to HMAC Validation: Overview.
MessageMAC in a single fieldConsider the case where the MessageMAC is contained entirely within a single field, as in this example URI path:
/download/cat.jpg?verify=1484063787-IaLGSmELTvlhfd0ItdN6PhhHTFhzx73EX8uy%2FcSDiIU%3D
Note how the URI maps to the elements of the MessageMAC:
Element Valuemessage
/download/cat.jpg
separator
?verify=
(with length 8
) timestamp
1484063787
mac
IaLGSmELTvlhfd0ItdN6PhhHTFhzx73EX8uy%2FcSDiIU%3D
When the MessageMAC is contained entirely within a single field such as http.request.uri
, pass the field name to the MessageMAC
argument of the HMAC validation function:
is_timed_hmac_valid_v0(
"mysecretkey",
http.request.uri,
100000,
http.request.timestamp.sec,
8
)
Concatenated MessageMAC argument
To compose a MessageMAC from more than one field, use the concat()
function.
This example constructs the value of the MessageMAC
argument by concatenating the request URI and two header fields:
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
)
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4