関数
Cloudflareのルール言語は、式内の値を操作および検証するための関数を提供します。
- 変換関数は、HTTPリクエストから抽出された値を操作します。
- HMAC検証関数は、HMACトークンの有効性をテストします。有効なHMACトークンの存在に基づいてリクエストをターゲットにする式を書くために使用します。
ルール言語は、HTTPリクエストから抽出された値を変換するいくつかの関数をサポートしています。変換関数の一般的な使用例は、文字列を大文字または小文字に変換することです。デフォルトでは、文字列の評価は大文字と小文字を区別します。
例えば、lower()関数は、文字列内のすべての大文字を小文字に変換します。
以下の式では、lower()関数がhttp.hostの値を小文字に変換し、ターゲット値"www.cloudflare.com"と一致させます:
lower(http.host) == "www.cloudflare.com"配列を引数として取らない変換関数は、[*]インデックス表記を必要とします。詳細については、配列を参照してください。
ルール言語は、以下の変換関数をサポートしています:
any(Array<Boolean>) → Boolean
引数の配列内の_任意_の値に対して比較演算子がtrueを返す場合、trueを返します。それ以外の場合はfalseを返します。
例:
any(url_decode(http.request.body.form.values[*])[*] contains "an xss attack")all(Array<Boolean>) → Boolean
引数の配列内の_すべて_の値に対して比較演算子がtrueを返す場合、trueを返します。それ以外の場合はfalseを返します。
例:
all(http.request.headers["content-type"][*] == "application/json")cidr(address (IP address), ipv4_network_bits (Integer), ipv6_network_bits (Integer)) → IP address
提供されたIPv4およびIPv6ネットワークビットに基づいて、IPアドレス(IPv4またはIPv6)に対応するネットワークアドレスを返します(これにより、対応するネットマスクが決まります)。
addressパラメータはフィールドでなければならず、リテラル文字列であってはなりません。
ipv4_network_bitsの値は1から32の間で、ipv6_network_bitsの値は1から128の間でなければなりません。
例:
ip.srcが113.10.0.2の場合、cidr(ip.src, 24, 24)は113.10.0.0を返します。ip.srcが2001:0000:130F:0000:0000:09C0:876A:130Bの場合、cidr(ip.src, 24, 24)は2001:0000:0000:0000:0000:0000:0000:0000を返します。
cidr6(address (IP address), ipv6_network_bits (Integer)) → IP address
提供されたネットワークビットに基づいて、IPv6アドレスに対応するIPv6ネットワークアドレスを返します。最初のパラメータにIPv4アドレスを提供した場合、それは変更されずに返されます。
addressパラメータはフィールドでなければならず、リテラル文字列であってはなりません。
ipv6_network_bitsの値は1から128の間でなければなりません。
この関数は次のように等価です:cidr(<address>, 32, <ipv6_network_bits>)。
例:
ip.srcが2001:0000:130F:0000:0000:09C0:876A:130Bの場合、cidr6(ip.src, 24)は2001:0000:0000:0000:0000:0000:0000:0000を返します。ip.srcが113.10.0.2の場合、cidr6(ip.src, 24)は113.10.0.2(変更なし)を返します。
concat(String | Integer | Bytes | Array elements) → String
カンマ区切りの値のリストを取ります。引数の値を単一の文字列に連結します。
例えば、concat("String1", " ", "String", 2)は"String1 String2"を返します。
decode_base64(source (String)) → String
sourceで指定されたBase64エンコードされた文字列をデコードします。
sourceはフィールドでなければならず、リテラル文字列であってはなりません。
例えば、次のHTTPリクエストヘッダーがある場合:client_id: MTIzYWJj、(any(decode_base64(http.request.headers["client_id"][*])[*] eq "123abc"))はtrueを返します。
ends_with(source (String), substring (String)) → Boolean
ソースが指定された部分文字列で終わる場合、trueを返します。それ以外の場合はfalseを返します。ソースはリテラル値(例えば"foo")であってはなりません。
例えば、http.request.uri.pathが"/welcome.html"の場合、ends_with(http.request.uri.path, ".html")はtrueを返します。
len(String | Bytes) → Integer
文字列またはバイトフィールドのバイト長を返します。
例えば、http.hostが"example.com"の場合、len(http.host)は11を返します。
lookup_json_integer(field (String), key (String | Integer) [, key (String | Integer), ...]) → Integer
指定されたkeyに関連付けられた整数値をfieldから返します。
fieldは有効なJSONドキュメントの文字列表現でなければなりません。
keyは属性名、JSON配列内のゼロベースの位置番号、またはこれらの2つのオプションの組み合わせ(追加の関数パラメータとして)であり、特定の整数値を取得するためにJSONドキュメントの階層に従う必要があります。
注意:この関数は、単純な整数にのみ機能します。例えば、42.0のような小数点以下がゼロの浮動小数点数には機能しません。
例:
-
次のJSONオブジェクトが
http.request.body.rawフィールドに含まれている場合:
{ "record_id": "aed53a", "version": 2 }
その場合、lookup_json_integer(http.request.body.raw, "version")は2を返します。 -
次のネストされたオブジェクトがある場合:
{ "product": { "id": 356 } }
その場合、lookup_json_integer(http.request.body.raw, "product", "id")は356を返します。 -
次のJSON配列がルートレベルにある場合:
["first_item", -234]
その場合、lookup_json_integer(http.request.body.raw, 1)は-234を返します。 -
次のJSONオブジェクト属性内の配列がある場合:
{ "network_ids": [123, 456] }
その場合、lookup_json_integer(http.request.body.raw, "network_ids", 0)は123を返します。 -
次のJSONオブジェクトのルートレベル配列がある場合:
[{ "product_id": 123 }, { "product_id": 456 }]
その場合、lookup_json_integer(http.request.body.raw, 1, "product_id")は456を返します。
lookup_json_string(field (String), key (String | Integer) [, key (String | Integer), ...]) → String
指定されたkeyに関連付けられた文字列値をfieldから返します。
fieldは有効なJSONドキュメントの文字列表現でなければなりません。
keyは属性名、JSON配列内のゼロベースの位置番号、またはこれらの2つのオプションの組み合わせ(追加の関数パラメータとして)であり、特定の値を取得するためにJSONドキュメントの階層に従う必要があります。
例:
-
次のJSONオブジェクトが
http.request.body.rawフィールドに含まれている場合:
{ "company": "cloudflare", "product": "rulesets" }
その場合、lookup_json_string(http.request.body.raw, "company") == "cloudflare"はtrueを返します。 -
次のネストされたオブジェクトがある場合:
{ "network": { "name": "cloudflare" } }
その場合、lookup_json_string(http.request.body.raw, "network", "name") == "cloudflare"はtrueを返します。 -
次のJSON配列がルートレベルにある場合:
["other_company", "cloudflare"]
その場合、lookup_json_string(http.request.body.raw, 1) == "cloudflare"はtrueを返します。 -
次のJSONオブジェクト属性内の配列がある場合:
{ "networks": ["other_company", "cloudflare"] }
その場合、lookup_json_string(http.request.body.raw, "networks", 1) == "cloudflare"はtrueを返します。 -
次のJSONオブジェクトのルートレベル配列がある場合:
[{ "network": "other_company" }, { "network": "cloudflare" }]
その場合、lookup_json_string(http.request.body.raw, 1, "network") == "cloudflare"はtrueを返します。
lower(String) → String
文字列フィールドを小文字に変換します。大文字のASCIIバイトのみが変換され、他のバイトは影響を受けません。
例えば、http.hostが"WWW.cloudflare.com"の場合、lower(http.host) == "www.cloudflare.com"はtrueを返します。
regex_replace(source (String), regular_expression (String), replacement (String)) → String
正規表現に一致するソース文字列の一部を置換文字列で置き換え、結果を返します。置換文字列には、正規表現のキャプチャグループへの参照(例えば、${1}や${2})を含めることができます。最大8つの置換参照が可能です。
例:
-
リテラルマッチ置換:
regex_replace("/foo/bar", "/bar$", "/baz") == "/foo/baz" -
一致しない場合、入力文字列は変更されません:
regex_replace("/x", "^/y$", "/mumble") == "/x" -
一致はデフォルトで大文字と小文字を区別します:
regex_replace("/foo", "^/FOO$", "/x") == "/foo" -
一致が複数ある場合、最初の1つだけが置換されます:
regex_replace("/a/a", "/a", "/b") == "/b/a" -
置換文字列内の
$をエスケープするには、別の$でプレフィックスを付けます:
regex_replace("/b", "^/b$", "/b$$") == "/b$" -
キャプチャグループを使用して置換:
regex_replace("/foo/a/path", "^/foo/([^/]*)/(.*)$", "/bar/${2}/${1}") == "/bar/path/a/"
キャプチャグループを作成するには、正規表現の一部を括弧で囲みます。次に、置換文字列内で${<NUMBER>}を使用してキャプチャグループを参照します。<NUMBER>はキャプチャグループの番号です。
remove_bytes(Bytes) → Bytes
指定されたバイトのすべての出現を削除した新しいバイト配列を返します。
例えば、http.hostが"www.cloudflare.com"の場合、remove_bytes(http.host, "\x2e\x77")は"cloudflarecom"を返します。
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(field (String | Bytes), start (Integer) [, end (Integer)]) → String
fieldの値(文字列またはバイトのフィールドの値)から、startバイトインデックスから(ただしendバイトインデックスを除く)までの部分を返します。field内の最初のバイトのインデックスは0です。オプションのendインデックスを提供しない場合、関数はstartインデックスから文字列の最後までの部分を返します。
startおよびendインデックスは負の整数値を取ることができ、これにより文字列の先頭ではなく末尾から文字をアクセスできます。
例:
// http.request.body.rawが"asdfghjk"の場合:
substring(http.request.body.raw, 2, 5) は"dfg"を返します。substring(http.request.body.raw, 2) は"dfghjk"を返します。substring(http.request.body.raw, -2) は"jk"を返します。substring(http.request.body.raw, 0, -2) は"asdfgh"を返します。to_string(Integer | Boolean | IP address) → String
整数、ブール値、またはIPアドレス値の文字列表現を返します。
例:
// cf.bot_management.scoreが5の場合:to_string(cf.bot_management.score) は"5"を返します。
// sslがtrueの場合:to_string(ssl) は"true"を返します。upper(String) → String
文字列フィールドを大文字に変換します。小文字のASCIIバイトのみが変換され、他のバイトは影響を受けません。
例えば、http.hostが"www.cloudflare.com"の場合、upper(http.host)は"WWW.CLOUDFLARE.COM"を返します。
url_decode(source (String)[, options (String)]) → String
sourceで定義されたURL形式の文字列をデコードします。以下のように:
-
%20および+はスペース文字()にデコードされます。 -
%E4%BDはä½にデコードされます。
sourceはフィールドでなければならず、リテラル文字列であってはなりません。
options パラメータはオプションです。オプションは、"r" や "ur" のように、引用符で囲まれた単一の文字列として提供する必要があります。利用可能なオプションは以下の通りです:
r: 再帰的デコードを適用します。例えば、%2520は2回(再帰的に)デコードされてスペース文字()になります。u: Unicodeパーセントデコードを有効にします。結果はUTF-8でエンコードされます。例えば、"%u2601"はUTF-8でエンコードされた雲の絵文字(☁️)にデコードされます("\xe2\x98\x81"、サイズは3バイト)。
例:
url_decode("John%20Doe") は "John Doe" を返しますurl_decode("John+Doe") は "John Doe" を返しますurl_decode("%2520") は "%20" を返しますurl_decode("%2520", "r") は " " を返します
// any() 関数と共に url_decode() を使用する場合:any(url_decode(http.request.body.form.values[*])[*] contains "an xss attack")uuidv4(Bytes) → String
指定された引数(ランダムのソース)に基づいてランダムなUUIDv4(ユニバーサルユニーク識別子、バージョン4)を生成します。ランダムなバイトの配列を取得するには、cf.random_seed フィールドを使用します。
例えば、uuidv4(cf.random_seed) は 49887398-6bcf-485f-8899-f15dbef4d1d5 に似たUUIDv4を返します。
wildcard_replace(source (Bytes), wildcard_pattern (Bytes), replacement (Bytes) [, flags (Bytes)]) → String
リテラルでゼロまたはそれ以上の * ワイルドカードメタキャラクタに一致する source 文字列を置き換え文字列で置き換え、結果を返します。置き換え文字列には、ワイルドカードキャプチャグループへの参照(例えば、${1} や ${2})を含めることができ、最大8つの置き換え参照が可能です。
一致がない場合、関数は source を変更せずに返します。
source パラメータはフィールドでなければなりません(リテラル文字列ではいけません)。さらに、source の全体の値は wildcard_pattern パラメータと一致しなければなりません(フィールド値の一部だけと一致してはいけません)。
wildcard_pattern パラメータにリテラル * 文字を入力するには、\* を使用してエスケープする必要があります。さらに、\ も \\ を使用してエスケープする必要があります。このパラメータ内で連続する2つのエスケープされていない * 文字(**)は無効と見なされ、使用できません。文字のエスケープを行う必要がある場合は、wildcard_pattern パラメータに対して 生文字列構文 を使用することをお勧めします。
replacement パラメータにリテラル $ 文字を入力するには、$$ を使用してエスケープする必要があります。
大文字と小文字を区別したワイルドカード一致を行うには、flags パラメータを "s" に設定します。
この関数は遅延一致を使用しており、各 * メタキャラクタを最短の文字列で一致させようとします。
例:
-
フルURIが
https://apps.example.com/calendar/admin?expand=trueの場合、
wildcard_replace(http.request.full_uri, "https://*.example.com/*/*", "https://example.com/${1}/${2}/${3}")はhttps://example.com/apps/calendar/admin?expand=trueを返します。 -
フルURIが
https://example.com/applications/app1の場合、
wildcard_replace(http.request.full_uri, "/applications/*", "/apps/${1}")はhttps://example.com/applications/app1を返します(一致がないため変更されていない値;URIパスの一致にはhttp.request.uri.pathフィールドを使用する必要があります)。 -
URIパスが
/calendarの場合、
wildcard_replace(http.request.uri.path, "/*", "/apps/${1}")は/apps/calendarを返します。 -
URIパスが
/Apps/calendarの場合、
wildcard_replace(http.request.uri.path, "/apps/*", "/${1}")は/calendarを返します(デフォルトでは大文字と小文字を区別しない一致)。 -
URIパスが
/Apps/calendarの場合、
wildcard_replace(http.request.uri.path, "/apps/*", "/${1}", "s")は/Apps/calendarを返します(変更されていない値); 一致が大文字と小文字を区別するため、一致がありません。 -
URIパスが
/apps/calendar/loginの場合、
wildcard_replace(http.request.uri.path, "/apps/*/login", "/${1}/login")は/calendar/loginを返します。
ワイルドカード一致のさらなる例については、ワイルドカード一致を参照してください。
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ビットを超えてはなりません。
is_timed_hmac_valid_v0() 関数を使用して、ルール式でハッシュベースのメッセージ認証コード(HMAC)トークンを検証できます。この関数のシグネチャは次のとおりです:
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() 関数のパラメータ定義は次のとおりです:
-
Key(String literal)- HMACを検証するための秘密の暗号鍵を指定します。
-
MessageMAC(String)- これらのHMAC要素の連結を含みます:
message、separator、timestamp、mac。定義と例については、MessageMACを参照してください。
- これらのHMAC要素の連結を含みます:
-
ttl(Integer literal)- HMACトークンの有効期限を秒単位で定義します。トークンが発行された時点からどれだけの間有効であるかを決定します。
-
currentTimeStamp(Integer)- Cloudflareがリクエストを受信したときのUNIXタイムスタンプを秒単位で表します。この引数には、
http.request.timestamp.secフィールドを近似値として渡します。
- Cloudflareがリクエストを受信したときのUNIXタイムスタンプを秒単位で表します。この引数には、
-
lengthOfSeparator(Integer literal, optional)MessageMAC内のtimestampとmessageの間のseparatorの長さを指定します。バイト単位で表し、デフォルト値は0です。
-
flags(String literal, optional)-
このオプション引数を
's'に設定すると、MessageMAC引数内のBase64エンコードされたmacの値がパディングなしのURLセーフ文字セットを使用することを期待します。 -
flagsの値を's'に設定しない場合、MessageMAC引数内のmacのBase64値をURLエンコードする必要があります。
-
is_timed_hmac_valid_v0() 関数は、提供された Key を使用して、MessageMAC の message と timestamp の領域からメッセージ認証コード(MAC)を生成します。生成されたMACが MessageMAC の mac 領域と一致し、トークンが期限切れでない場合、HMACは有効であり、関数は true を返します。
例えば、次の式は、正しいHMACトークンを含まない downloads.example.com へのリクエストに一致します:
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は次の正規表現を満たします:
(.+)(.*)(\d{10})-(.{43,})およびこれらの括弧で区切られた式で構成されています:
| 式 | 説明 | 例 |
|---|---|---|
(.+) | 検証する message。 | /download/cat.jpg |
(.*) | メッセージとタイムスタンプの間の separator、一般的にはパラメータ名。 | &verify= |
(\d{10}) | MACが発行されたときの10桁のUNIX timestamp、秒単位で表現。 | 1484063137 |
(.{43,}) | mac のBase64エンコードバージョン。HMAC検証関数の urlSafe 引数の値を 's' に設定しない場合、mac のBase64値をURLエンコードする必要があります。Base64 MACエンコーディングがURLセーフな場合、mac 値は43バイトを含みます。そうでない場合、値はURLエンコーディングのため44バイト以上になります。 | IaLGSmELTvlhfd0ItdN6PhhHTFhzx73EX8uy%2FcSDiIU%3D |
MessageMACの生成に関する詳細は、HMACトークン生成を参照してください。
MessageMACが単一フィールド内に完全に含まれている場合を考えます。この例のURIパス:
/download/cat.jpg?verify=1484063787-IaLGSmELTvlhfd0ItdN6PhhHTFhzx73EX8uy%2FcSDiIU%3DURIがMessageMACの要素にどのようにマッピングされるかに注意してください:
| 要素 | 値 |
|---|---|
message | /download/cat.jpg |
separator | ?verify=(長さ 8) |
timestamp | 1484063787 |
mac | IaLGSmELTvlhfd0ItdN6PhhHTFhzx73EX8uy%2FcSDiIU%3D |
MessageMACが http.request.uri のような単一フィールド内に完全に含まれている場合、HMAC検証関数の MessageMAC 引数にフィールド名を渡します:
is_timed_hmac_valid_v0( "mysecretkey", http.request.uri, 100000, http.request.timestamp.sec, 8)複数のフィールドからMessageMACを構成するには、concat() 関数を使用します。
この例では、リクエストURIと2つのヘッダーフィールドを連結して MessageMAC 引数の値を構築します:
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)