HTTP リクエストが Cloudflare のグローバルネットワークに到達すると、Cloudflare は式の照合用にフィールドと値のペアの表を作ります。この表は、現在のリクエストの処理中だけ存在します。
Rules 言語のルックアップ表を埋める値は、さまざまなソースから得られます。
- プリミティブなプロパティ はリクエストから直接取得します(例:
http.request.uri.path)。 - 派生値 は変換、合成、または基本演算の結果です。たとえば、変換
lower(http.request.uri.path)はhttp.request.uri.pathの値を小文字にします。 - 計算値 はルックアップ、計算、またはそのほかの判定の結果です。たとえば、Cloudflare は機械学習で攻撃スコアを動的に算出し、
cf.waf.score*フィールドで表します。
これらの値に加え、式にはリテラル値も含められます。リテラルは静的で既知の値です。変換の有無にかかわらず、リクエスト/レスポンスフィールドの値と比較するために式へ組み込みます。
ルール式で値を扱うときは、以降の各節の内容を念頭に置いてください。
文字列は、特定の区切り文字で囲んだバイト列です。
Cloudflare のルールは、正規表現を含むリテラル文字列の指定に 2 つの形式を使えます。引用符付き文字列 と raw 文字列 です。区切り文字とエスケープの仕組みが異なります。
式の正規表現には、どちらの文字列形式も使えます。ただし、引用符付き文字列はエスケープ規則が複雑で、十分にテストしないと想定外の動作につながることがあります。Cloudflare は raw 文字列構文 の使用を推奨します。
正規表現の照合には、Rust の正規表現エンジンを使います。
引用符付き文字列構文では、文字列リテラルを "(二重引用符)で区切ります。この形式では、特殊文字 " と \ をそれぞれ \" と \\ でエスケープする必要があります。
引用符付き文字列構文には、次の追加のエスケープ要件があります。
- 正規表現演算子(
matchesまたは~)の右辺で正規表現を指定する場合、文字列は正規表現のエスケープ規則で解析されます。 - ほかの演算子の右辺、または 関数パラメーター で使う場合、文字列は基本的なエスケープ規則で解析されます。
# 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", "\\")raw 文字列構文で文字列(または正規表現)を指定するには、次の特別な区切り文字を使います。
- 開始区切りは、
rのあとに任意で 1 個以上の#(最大 255 個)を付け、続けて"(二重引用符)です。 - 終了区切りは、
"(二重引用符)のあとに、開始区切りと同じ個数の#(0〜255)です。
raw 文字列には特殊文字がありません。終了区切りまでのすべての文字はそのまま解釈されます(エスケープシーケンスはありません)。
引用符付き文字列構文と異なり、raw 文字列構文は使う文脈に関係なく常に同じです(たとえば、正規表現演算子 付きの正規表現でも、関数呼び出し のパラメーターでも同じです)。
# 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$"式での文字列リテラルの評価は大文字小文字を区別します。大文字小文字の違いを拾うには、次のいずれかを検討してください。
- 文字列リテラルの照合に、大文字小文字を区別しない
wildcard演算子を使います。 - 比較前に
lower()関数で文字列を小文字にします。 - 異なる表記に一致する正規表現と
matches演算子を使います(Business プランと Enterprise プランのみ)。 eqまたはcontains演算子の部分式を、or演算子でつなぎ、文字列リテラルの複数の表記を拾います(例:<field> eq "a" or <field> eq "A")。
Cloudflare には、正規表現に関するいくつかの上限があります。その 1 つは、ドメインのプランにかかわらず、各ルールが最大 64 個の正規表現(regex)までという制限です。
ルール内の正規表現の数を減らすには、次の方法を使えます。
contains演算子を使う。wildcard/strict wildcard演算子を使う。starts_with()とends_with()関数を使う。
真偽値フィールドを使う単純な式では、演算子の記法や値は不要です。次の ssl の例のように、フィールドだけを置きます。
sslこの単純な式は、ssl フィールドの値が true のリクエストに一致します。
ssl が false のリクエストに一致させるには、真偽値の not 演算子を使います。
not sslCloudflare Rules 言語には Array 型の フィールド と、Array の引数・戻り値を持つ 関数 があります。
個々の配列要素には、角括弧([])で囲んだインデックス(非負の値)でアクセスできます。配列のインデックスは 0(ゼロ)から始まります。
各配列要素に対して評価する式を指定するときは、特別な記法 [*] を使います(map 高階関数 ↗ と同様です)。この特別なインデックス記法は配列を展開し、囲んでいる関数を各要素に対して個別に呼び、個々の戻り値を含む新しい配列を返します。
次の例では、型が Array<String> の http.request.headers.names フィールドを使います。
-
配列の最初の要素を取得する:
http.request.headers.names[0] -
最初の配列要素が
Content-Typeと等しいかを確認する(大文字小文字を区別):
http.request.headers.names[0] == "Content-Type" -
いずれかの配列要素が
Content-Typeと等しいかを確認する(大文字小文字を区別):
any(http.request.headers.names[*] == "Content-Type") -
大文字小文字を無視して、いずれかの配列要素が
Content-Typeと等しいかを確認する:
any(lower(http.request.headers.names[*])[*] == "content-type")
最後の例では、lower() 関数に [*] 記法を付け、各配列要素に対して関数を評価します。[*] と一緒に使うと、入力配列の各要素を小文字にした新しい配列を返します。次に、文字列比較が [*] を使い、各ヘッダー名に lower() を適用した結果の配列を真偽値の配列に変換します。最後に、これらの配列要素の少なくとも 1 つが true なら any() は true になります。
独自の配列は定義できません。フィールドが返す配列だけを、直接または関数で加工して使えます。
an out-of-bounds array index にアクセスすると missing value(欠落値)になります。missing value の動作は次のとおりです。
<expr>が missing value になる比較<expr> <op> <literal>は、false と評価されます。function(<expr>)のような関数呼び出しで<expr>が missing value になる場合、多くの場合 missing value を返します。ただし正確な動作は関数ごとに異なります。
同じ式で [*] を複数回使えるのは、同じ配列に適用する場合だけです。また、[*] を使えるのは関数呼び出しの最初の引数だけです。
Rules 言語の 演算子 は、配列や [*] 演算子を直接はサポートしません。ただし、array_value[0] のようなインデックス付き配列要素はサポートします。たとえば、囲んでいる関数呼び出しの外で == 演算子と [*] は使えません。
http.request.headers.names[*] == "Content-Type"— 無効 な式any(http.request.headers.names[*] == "Content-Type")— 有効 な式
マップ(連想配列とも呼ばれます)は、キーと値のペアの集まりを格納するデータ構造です。キーは String で、値は任意の型(例: String または値の配列)にできます。マップ内の値はすべて同じ型である必要があります。
Cloudflare Rules 言語には、Map データ型の フィールド がいくつかあります。マップフィールドの型記法(例: Map<Array<String>>)は、キーに関連付けられた値のデータ型(String 要素の Array)を示します。つまり、キー "foo" の値にアクセスすると、String 要素の配列か 欠落値 が得られます。
マップの値にアクセスするには、角括弧([])でキーを囲みます。
<MAP_FIELD>[<KEY>]値が Array 型のマップでは、取得した(配列の)値に 演算子 を直接使えません。演算子は配列を直接サポートしないためです。配列の要素に演算子を使うには、式を指定するときに特別な記法 [*] を使います。この特別なインデックス記法は配列を展開し、囲んでいる関数を各要素に対して個別に呼び、個々の戻り値を含む新しい配列を返します。
次の例は、データ型が Map<Array<String>> の http.request.headers フィールドに基づきます。配列要素の型は String です。
受信 HTTP リクエストに Accept: application/json HTTP ヘッダーが 1 つ含まれていた場合、次の式は示した値に評価されます。
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") # ==> false次の例は、データ型が Map<Array<String>> の http.request.uri.args フィールドに基づきます。配列要素の型は String です。
HTTP リクエストに 3 つの filter URI 引数 waf、botm、cdn が含まれていた場合、次の式は示した値に評価されます。
# 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 # ==> trueany()、all()、len()、そのほかの利用可能な関数の詳細は 関数 を参照してください。
独自のマップは定義できません。フィールドが返すマップだけを使えます。
a non-existing key in a map にアクセスすると missing value(欠落値)になります。missing value の動作は次のとおりです。
<expr>が missing value になる比較<expr> <op> <literal>は、false と評価されます。function(<expr>)のような関数呼び出しで<expr>が missing value になる場合、多くの場合 missing value を返します。ただし正確な動作は関数ごとに異なります。
リストを使うと、項目のグループを作り、式の中で名前でまとめて参照できます。各リスト型は特定のデータ型の項目をサポートします。リスト内の項目はすべて同じデータ型である必要があります。利用できるリスト型の詳細は リスト を参照してください。
ルール式でリストを参照するには $<list_name> を使い、in 演算子 を指定します。リスト内の値が 1 つでも式の左辺(in 演算子の前)に一致すれば、単純な式は true になります。一致がなければ式は false になります。
次の例の式は、office_network という名前の IP リスト に含まれる IP アドレスからのリクエストをフィルターします。
(ip.src in $office_network)リスト名に使えるのは、小文字、数字、アンダースコア(_)だけです。リストの作成と管理の指針は リスト を参照してください。
インラインリストを使うと、in 演算子を使う単純な式に、値のリストを直接含められます。
インラインリストの要素は、文字列、整数、または IP アドレス/範囲にできます。インラインリストの要素はすべて同じデータ型で、リテラル値である必要があります。インラインリストの要素は個別に入力し、スペースで区切ります。インラインリストには重複した値を含められます。
加えて、一部のデータ型では要素として範囲を使えます。
-
整数値では、範囲を
<start_value>..<end_value>の形式で入力します。インラインリストには整数範囲と整数値の両方を含められます。 -
IP アドレスでは、次を入力できます。
<start_address>..<end_address>形式の明示的な IP 範囲(例:198.51.100.3..198.51.100.7)。- CIDR 範囲(例:
192.0.2.0/24または2001:0db8::/32)。
インラインリストには、明示的な IP 範囲、CIDR 範囲、個別の IP アドレスを含められます。
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}