← Cloudflare Ruleset Engine / ruleset-engine / rules-language
Hodnoty
Když HTTP požadavek dorazí do globální sítě Cloudflare, Cloudflare vytvoří tabulku párů pole-hodnota, vůči které se porovnávají výrazy. Tato tabulka existuje po celou dobu zpracování aktuálního požadavku.
Hodnoty, které naplňují vyhledávací tabulky Rules language, pocházejí z různých zdrojů:
- Primitivní vlastnosti se získávají přímo z požadavku (
http.request.uri.path, například). - Odvozené hodnoty jsou výsledkem transformace, kompozice nebo základní operace. Například transformace
lower(http.request.uri.path)převádí hodnotuhttp.request.uri.pathna malá písmena. - Vypočítané hodnoty jsou výsledkem vyhledávání, výpočtu nebo jiné analýzy. Cloudflare například pomocí procesu strojového učení dynamicky vypočítává skóre útoku, které je reprezentováno
cf.waf.score*pole.
Kromě těchto hodnot mohou výrazy obsahovat i doslovné hodnoty. Jde o statické, předem známé hodnoty, které do výrazů vkládáte, abyste je porovnali s hodnotami z polí požadavku nebo odpovědi, ať už transformovanými, nebo ne.
Při práci s hodnotami ve výrazech pravidel mějte na paměti informace uvedené v následujících částech.
Řetězcové hodnoty a regulární výrazy
Řetězce jsou posloupnosti bajtů ohraničené specifickými oddělovači.
Pravidla Cloudflare podporují dva formáty zápisu doslovných řetězců, včetně regulárních výrazů: uvozené řetězcové literály a surové řetězce. Tyto formáty mají odlišné oddělovače a mechanismy escapování.
K zadání regulárních výrazů ve výrazu můžete použít kterýkoli ze dvou formátů řetězců. Cloudflare však doporučuje použít syntaxe surových řetězců, protože syntaxe řetězce v uvozovkách má složitá pravidla pro escapování a při nedostatečném otestování může vést k neočekávanému chování.
Porovnávání pomocí regulárních výrazů se provádí pomocí enginu regulárních výrazů jazyka Rust.
Syntaxe řetězce v uvozovkách
Při použití syntaxe řetězce v uvozovkách je řetězcový literál ohraničen " (znaky dvojité uvozovky). Tento formát vyžaduje escapování speciálních znaků " a \ pomocí \" a \\, v uvedeném pořadí.
Syntaxe řetězce v uvozovkách má následující další požadavky na escapování:
- Při použití k zadání regulárního výrazu na pravé straně operátor regex (
matchesnebo~), řetězec se zpracovává podle pravidel escapování pro regulární výrazy. - Při použití na pravé straně výrazů s jinými operátory nebo v parametry funkce, je řetězec zpracován podle základních pravidel pro escapování.
# Test if URI path contains 'a"b'
http.request.uri.path matches "a\"b"
# Test if URI path contains 'a"#b'
http.request.uri.path matches "a\"#b"
# Replace 'a' with '\' (backslash)
regex_replace(http.host, "a", "\\")Syntaxe nezpracovaného řetězce
Chcete-li zadat řetězec (nebo regulární výraz) pomocí syntaxe nezpracovaného řetězce, použijte speciální oddělovače:
- Počáteční oddělovač se skládá z
rznak, za kterým volitelně následuje jeden nebo více#znaků (až 255), za kterými následuje"(znak dvojité uvozovky). - Koncový oddělovač je
"(znak dvojité uvozovky), za kterým následuje stejný počet#znaků jako v počátečním oddělovači (od 0 do 255).
V surovém řetězci (raw string) nejsou žádné speciální znaky, takže všechny znaky až po koncový oddělovač se interpretují doslovně (nejsou zde žádné escape sekvence).
Na rozdíl od syntaxe řetězce v uvozovkách je syntaxe nezpracovaného řetězce vždy stejná bez ohledu na kontext, ve kterém se používá (například jako regulární výraz s operátor regex nebo jako parametr volání funkce).
# Test if URI path contains 'a"b'
http.request.uri.path matches r#"a"b"#
# Test if URI path contains 'a"#b'
http.request.uri.path matches r##"a"#b"##
# Replace '\' (backslash) with 'a'
# You must still escape the '\' character in the following raw string because it has a special meaning in regular expressions
regex_replace(http.host, r"\\", "a")
# Test if URI path ends with '/api/login.aspx'
# You must still escape the '.' character in the following raw string because it has a special meaning in regular expressions ("any character")
http.request.uri.path matches r"/api/login\.aspx$"Rozlišování velkých a malých písmen při porovnávání řetězců
Vyhodnocování řetězcových literálů ve výrazech rozlišuje velká a malá písmena, proto pro zachycení různých variant velikosti písmen ve výrazu zvažte některou z následujících možností:
- Použijte
wildcardoperátor, který nerozlišuje velikost písmen, pro porovnání s řetězcovým literálem. - Použijte
lower()funkci, abyste řetězec před porovnáním převedli na malá písmena. - Použijte
matchesoperátor (dostupný pouze v plánech Business a Enterprise) s regulárním výrazem, který odpovídá různým variantám. - Napište několik dílčích výrazů s
eqnebocontainsoperátor, spojený soroperátor, abyste zachytili různé varianty řetězcového literálu (například<field> eq "a" or <field> eq "A").
Limity regulárních výrazů
Cloudflare uplatňuje pro regulární výrazy několik omezení. Jedním z nich je, že každé pravidlo podporuje maximálně 64 regulárních výrazů (regexů), a to bez ohledu na plán vaší domény.
Počet regulárních výrazů v pravidle můžete snížit pomocí následujících postupů:
- Použijte
containsoperátor. - Použijte
wildcard/strict wildcardoperátory. - Použijte
starts_with()aends_with()funkce.
Booleovské hodnoty
Jednoduché výrazy používající booleovská pole nevyžadují zápis operátoru ani hodnotu. Stačí vložit samotné pole, jak ukazuje ssl příklad níže.
sslTento jednoduchý výraz odpovídá požadavkům, u kterých hodnota ssl pole je true.
Chcete-li porovnávat požadavky, kde ssl je false, použijte booleovský not operátor :
not sslPole
Cloudflare Rules language obsahuje pole z Array typu a funkce hodnotou Array argumenty a návratové hodnoty.
K jednotlivým prvkům pole můžete přistupovat pomocí indexu (nezáporné hodnoty) v hranatých závorkách ([]). Indexy pole začínají na 0 (nula).
Použijte speciální notaci [*] při zadávání výrazu, který se vyhodnotí pro každý prvek pole (například map funkce vyššího řádu ↗). Tato speciální indexová notace rozbalí pole, zavolá obklopující funkci pro všechny jeho prvky jednotlivě a vrátí nové pole obsahující všechny jednotlivé návratové hodnoty.
Příklady
Podívejte se na http.request.headers.names pole s typem Array<String> v následujících příkladech:
-
Získání prvního prvku pole:
http.request.headers.names[0] -
Zkontrolujte, zda se první prvek pole rovná
Content-Type(rozlišuje velká a malá písmena):
http.request.headers.names[0] == "Content-Type" -
Zkontrolujte, zda se některý prvek pole rovná
Content-Type(rozlišuje velká a malá písmena):
any(http.request.headers.names[*] == "Content-Type") -
Zkontrolujte, zda se některý prvek pole rovná
Content-Type, bez ohledu na velikost písmen:
any(lower(http.request.headers.names[*])[*] == "content-type")
V posledním příkladu lower() funkce obsahuje [*] notaci, aby se funkce vyhodnotila pro každý prvek pole. Tato funkce, použitá spolu s [*], vrátí nové pole, ve kterém je každý prvek vstupního pole převeden na malá písmena. Poté se při porovnání řetězců použije [*] k transformaci pole, které vznikne použitím lower() na název každé hlavičky do pole booleovských hodnot. Nakonec any() vyhodnotí jako true, pokud je true alespoň jeden z prvků tohoto pole.
Poznámky
Vlastní pole (arrays) není možné definovat. Můžete používat pouze pole vrácená poli (fields), přímo nebo upravená funkcemi.
Přístup k indexu pole mimo rozsah vytvoří „chybějící hodnotu“. Chybějící hodnota se chová takto:
- Jakékoli porovnání
<expr> <op> <literal>kde<expr>vyhodnotí jako chybějící hodnotu, vyhodnotí se jako false. - Volání funkcí, jako je
function(<expr>), kde<expr>vyhodnotí jako chybějící hodnotu, ve většině případů vrátí chybějící hodnotu, ale přesné chování se může lišit podle konkrétní funkce.
Můžete použít pouze [*] vícekrát ve stejném výrazu, pokud se použije na stejné pole. Rovněž lze použít pouze [*] v prvním argumentu volání funkce.
Rules language operátory přímo nepodporují pole ani [*] operátor. Podporují však indexované prvky pole, jako je array_value[0]. Nemůžete například použít [*] hodnotou == operátor mimo kontext obklopujícího volání funkce:
http.request.headers.names[*] == "Content-Type", Neplatné výrazany(http.request.headers.names[*] == "Content-Type"), Platné výraz
Mapy
Mapa, také nazývaná asociativní pole, je datová struktura, která uchovává kolekci párů klíč-hodnota, přičemž klíč musí být String a hodnota může být libovolného typu (například String nebo pole hodnot). Všechny hodnoty v mapě musí mít stejný typ.
Cloudflare Rules language obsahuje několik pole z Map datový typ. Zápis typu pro pole typu map, například Map<Array<String>>, udává datový typ hodnot přiřazených ke klíčům (typu Array z String prvků). To znamená, že když přistupujete k hodnotě klíče "foo" získáte buď pole String prvků nebo chybějící hodnota.
Chcete-li přistoupit k hodnotě v mapě, zadejte klíč do hranatých závorek ([]):
<MAP_FIELD>[<KEY>]U map, jejichž hodnoty mají Array typu nemůžete přímo použít operátory se získanou hodnotou (polem), protože tyto operátory nepodporují pole přímo. Chcete-li použít operátor na prvek pole, použijte speciální notaci [*] při zadávání výrazu. Tato speciální indexová notace rozbalí pole, zavolá obklopující funkci pro všechny jeho prvky jednotlivě a vrátí nové pole obsahující všechny jednotlivé návratové hodnoty.
Příklady
Následující příklad vychází z http.request.headers pole s datovým typem Map<Array<String>>, kde jsou prvky pole typu String datový typ.
Pokud příchozí HTTP požadavek obsahoval jeden Accept: application/json HTTP hlavička, by se následující výrazy vyhodnotily na uvedené hodnoty:
http.request.headers["accept"] # ==> ["application/json"]
http.request.headers["accept"][0] # ==> "application/json"
any(http.request.headers["accept"][*] == "application/json") # ==> true
any(http.request.headers["accept"][*] == "text/plain") # ==> falseNásledující příklad vychází z http.request.uri.args pole s datovým typem Map<Array<String>>, kde jsou prvky pole typu String datový typ.
Pokud HTTP požadavek obsahoval tři filter argumenty URI waf, botm, a cdn, by se následující výrazy vyhodnotily na uvedené hodnoty:
# Example request URL:
# https://example.com/?filter=waf&filter=botm&filter=cdn
http.request.uri.args["filter"] # ==> ["waf", "botm", "cdn"]
len(http.request.uri.args["filter"][1]) # ==> 4
# Check if the length of all 'filter' values is always 3 or 4
all(len(http.request.uri.args["filter"][*])[*] in {3 4}) # ==> true
# Check if the length of 'filter' values (if any) is never 3 or 4
all(not len(http.request.uri.args["filter"][*])[*] in {3 4}) # ==> false
# Check if the http.request.uri.args map contains a "filter" key
len(http.request.uri.args["filter"]) >= 0 # ==> true
# Check if the http.request.uri.args map does not contain an "order" key
not len(http.request.uri.args["order"]) >= 0 # ==> trueVíce informací o any(), all(), len(), a dalších dostupných funkcích najdete v Funkce.
Poznámky
Vlastní mapy (maps) není možné definovat. Můžete používat pouze mapy vrácené poli (fields).
Přístup k neexistujícímu klíči v mapě vytvoří „chybějící hodnotu“. Chybějící hodnota se chová takto:
- Jakékoli porovnání
<expr> <op> <literal>kde<expr>vyhodnotí jako chybějící hodnotu, vyhodnotí se jako false. - Volání funkcí, jako je
function(<expr>), kde<expr>vyhodnotí jako chybějící hodnotu, ve většině případů vrátí chybějící hodnotu, ale přesné chování se může lišit podle konkrétní funkce.
Seznamy
Seznamy (lists) umožňují vytvořit skupinu položek a odkazovat se na ně ve výrazech společně, pod jedním názvem. Každý typ seznamu podporuje položky konkrétního datového typu. Všechny položky v seznamu musí mít stejný datový typ. Podrobnosti o dostupných typech seznamů najdete v Seznamy.
Chcete-li odkázat na seznam ve výrazu pravidla, použijte $<list_name> a zadat in provozovatel. Stačí, aby se jedna hodnota ze seznamu shodovala s levou stranou výrazu (před in operátor), aby se jednoduchý výraz vyhodnotil na true. Pokud nedojde ke shodě, výraz se vyhodnotí na false.
Následující příklad výrazu filtruje požadavky z IP adres, které se nacházejí v Seznam IP adres s názvem office_network:
(ip.src in $office_network)Názvy seznamů mohou obsahovat pouze malá písmena, číslice a podtržítko (_) znak. Pokyny k vytváření a správě seznamů najdete v Seznamy.
Vložené seznamy
Vložené seznamy umožňují přímo zahrnout seznam hodnot do jednoduchého výrazu, který používá in operátor.
Prvky vloženého seznamu mohou být řetězce, celá čísla nebo IP adresy/rozsahy. Všechny prvky vloženého seznamu musí mít stejný datový typ a musí jít o literální hodnoty. Chcete-li zadat prvky vloženého seznamu, zadejte je jednotlivě a oddělte je mezerou. Vložené seznamy mohou obsahovat duplicitní hodnoty.
U některých datových typů navíc můžete jako prvky použít rozsahy:
-
U celočíselných hodnot zadejte rozsahy ve tvaru
<start_value>..<end_value>. Vložený seznam může obsahovat jak rozsahy celých čísel, tak celočíselné hodnoty. -
U IP adres můžete zadat:
- Explicitní rozsahy IP adres ve tvaru
<start_address>..<end_address>(například198.51.100.3..198.51.100.7). - Rozsahy CIDR (například
192.0.2.0/24nebo2001:0db8::/32).
Vložený seznam může obsahovat explicitní rozsahy IP adres, rozsahy CIDR a jednotlivé IP adresy.
- Explicitní rozsahy IP adres ve tvaru
http.host in {"example.com" "example.net"}
ip.src in {198.51.100.1 198.51.100.3..198.51.100.7 192.0.2.0/24 2001:0db8::/32}
tcp.dstport in {8000..8009 8080..8089}