使用字段、函数和表达式
除操作外,字段和表达式也是 WAF 自定义规则的构建模块。 在定义匹配自定义规则时要使用的标准时,这两个元素会共同发挥作用。
字段
CIS 收到 HTTP 请求时,会检查该请求,并生成与之相匹配的字段表。 此字段表在当前请求处理期间始终存在。 请将其视为用于保存要与表达式匹配的请求属性的一个表。
每个字段值可以源自不同位置,例如:
- 原语属性,直接从流量中获取 - 例如
http.request.uri.path
。 - 派生值,由转换、组合或基本操作产生--例如,将
http.request.uri.path
的值全部小写并作为另一个字段的字段。 - 计算机值,通过查找、计算或其他智能功能生成 - 例如,由用于检查相关原语值和派生值的机器学习过程动态计算的
cf.threat_score
。
可用字段
字段名称 | Type | 示例值 | 注释 |
---|---|---|---|
http.cookie | 字符串 | session=A12345;-background=light | 作为字符串的整个 cookie |
http.host | 字符串 | www.example.com |
在完整请求 URI 中使用的主机名 |
http.referer | 字符串 | HTTP 引用头 | |
http.request.full_uri | 字符串 | https://www.example.com/articles/index?section=539061&expand=comments |
Web 服务器收到的完整 URI(不包括未发送到 Web 服务器的 #fragment ) |
http.request.method | 字符串 | POST | HTTP 方法(大写) |
http.request.uri | 字符串 | /articles/index?section=539061&expand=comments | 请求的绝对 URI |
http.request.uri.path | 字符串 | /articles/index | 请求的路径 |
http.request.uri.query | 字符串 | section=539061&expand=comments | 整个查询字符串,去掉定界前缀“?” |
http.user_agent | 字符串 | Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36 | 整个 HTTP 用户代理 |
http.x_forwarded_for | 字符串 | 完整的 X-Forwarded-For HTTP 标头 | |
ip.src | IP 地址 | 93.155.208.22 | 客户端 TCP IP 地址,可酌情调整以反映原始客户端的真实客户端 IP(例如,使用 HTTP 标头,如 X-Forwarded-For 或 X-Real-IP) |
ip.geoip.asnum | 编号 | 222 | 自治系统 (AS) 编号 |
ip.geoip.country | 字符串 | GB | 2位字母的国家代码 |
ssl | 布尔值 | 是 | 客户机的 HTTP 连接是否已加密 |
这些标准字段遵循 Wireshark 显示字段引用的命名约定。 然而,前面的示例值可能存在一些细微的差异。
除标准字段外,还提供以下 Cloudflare 定义的字段:
字段名称 | Type | 示例值 | 注释 |
---|---|---|---|
cf.client.bot | 布尔值 | 是 | 此字段指示请求是否来自已知机器人或搜寻器,无论其意图好坏。 |
cf.threat_score | 编号 | 0-100 之间的值 | 此字段表示风险分数,0 指示由 Cloudflare 确定的低风险。 超过 10 的数值可能代表垃圾邮件发送者或机器人,而超过 40 的数值则代表互联网上的不良行为者。 60 以上的值很少见,因此要调整 WAF 自定义规则,挑战 10 以上的值,并阻止 50 以上的值。 |
函数
自定义规则语言有许多转换字段的功能。
表达式生成器目前不支持这些功能。
函数名 | 自变量类型 | 返回类型 | 用法示例 | 注释 |
---|---|---|---|---|
lower | 字符串 | 字符串 | lower(http.host) == "www.example.com" |
将字符串字段转换为小写。 仅转换大写 ASCII 字节,其他每个字节都保留原样。 |
upper | 字符串 | 字符串 | upper(http.host) == "www.example.com" |
将字符串字段转换为大写。 仅转换小写 ASCII 字节,其他每个字节都保留原样。 |
表达式
表达式根据与入局流量的匹配情况返回 true 或 false。 例如:
http.host eq "www.example.com" and ip.src in 92.182.212.0/24
在本例中,两个单一表达式组成了一个复合表达式。 请将每个单一表达式视为一个条件。 每个条件会分别进行求值,然后再应用任何逻辑以确定复合表达式的最终结果。
从第一个单一表达式中可以看出,它包含了
- 字段 -
http.host
- 比较运算符 -
eq
- 值 -
"www.example.com"
并非所有条件都具有相同的结构。 在下一部分中将讨论使用不同结构的其他示例。
比较运算符
以下比较运算符可用于表达式:
英语 | 类 C | 描述 |
---|---|---|
eq | == | 等于 |
ne | != | 不等于 |
lt | < | 小于 |
le | <= | 小于或等于 |
GT | > | 大于 |
ge | >= | 大于或等于 |
contains | 完全包含 | |
匹配 | ~ | Re2 激发的正则表达式 |
in | 值出现在一组值中。 支持使用"... "符号的范围。 | |
not | ! | 请参阅“布尔值比较” |
bitwise_and | & | 比较位字段值 |
目前,表达式生成器只支持英文运算符。
一个表达式可能包含英语和类似 C 语言的混合运算符。 例如,ip.src eq 93.184.216.34
等效于 ip.src == 93.184.216.34
。
某些比较运算符适用于基于类型的特定字段。 以下矩阵提供了可用于各种字段类型的运算符的示例:
英语 | 类 C | 字符串 | IP 地址 | 编号 |
---|---|---|---|---|
eq | == | http.request.uri.path eq "/articles/2008/" | ip.src eq 93.184.216.0 | cf.threat_score eq 10 |
ne | != | http.request.uri.path ne "/articles/2010/" | ip.src ne 93.184.216.0 | cf.threat_score ne 60 |
lt | < | http.request.uri.path lt "/articles/2009/" | cf.threat_score lt 10 | |
le | <= | http.request.uri.path le "/articles/2008/" | cf.threat_score le 20 | |
GT | > | http.request.uri.path gt "/articles/2006/" | cf.threat_score gt 25 | |
ge | >= | 大于或等于 | cf.threat_score ge 60 | |
contains | http.request.uri.path contains "/articles/" | |||
匹配 | ~ | http.request.uri.path ~ " [^/articles/2007-8/$] " | ||
in | http.request.method in { "HEAD" "GET" } | ip.src in { 93.184.216.0 93.184.216.1 } | cf.threat_score in {0 2 10} |
对使用字符串值的表达式求值是区分大小写的。 因此,自定义规则可能需要定义多个测试条件。 企业客户可以使用包含匹配运算符的正则表达式来捕获单个表达式的多个变体。
布尔值比较
对于布尔值类型的字段(例如,ssl
),当求值为 true 条件时,该字段本身会出现在表达式中。 对于 false 条件,会应用 not 运算符。
True | 错 |
---|---|
ssl | not ssl |
复合表达
可以通过使用逻辑运算符对两个或更多单一表达式分组,以创建复合表达式。
英语 | 类 C | 描述 | 示例 | 优先顺序 |
---|---|---|---|---|
not | ! | 逻辑 NOT | not ( http.host eq "www.example.com" and ip.src in 93.184.216.0/24 ) |
1 |
和 | && | 逻辑 AND | http.host eq "www.example.com" and ip.src in 93.184.216.0/24 |
2 |
xor | ^^ | 逻辑 XOR | http.host eq "www.example.com" xor ip.src in 93.184.216.0/24 |
3 |
或 | || | 逻辑 OR | http.host eq "www.example.com" or ip.src in 93.184.216.0/24 |
4 |
要更改优先顺序,可以使用括号对表达式分组。 不使用括号时,表达式将根据标准优先顺序隐式分组:
ssl and http.request.uri.path eq /login or http.request.uri.path eq /oauth
应用显式分组:
(ssl and http.request.uri.path eq /login) or http.request.uri.path eq /oauth
给予优先顺序或使用括号:
ssl and (http.request.uri.path eq /login or http.request.uri.path eq /oauth)
请注意,虽然 not
用于分组,但只能用于否定单个比较。 例如,not ip.src eq 93.184.216.0
等效于 not (ip.src eq 93.184.216.0)
。
最后,还可以否定分组表达式:
not (http.request.method eq "POST" and http.request.uri.path eq "/login")
与 Wireshark 显示过滤器的偏差
自定义规则表达式的灵感来自 Wireshark 显示过滤器。 但是,实现在以下方面有偏差:
- 对于 CIDR IP 等同性测试,Wireshark 允许使用格式为
ip.src == 1.2.3.0/24
的范围,而 CIS 仅支持使用单个 IP 地址进行等同性测试。 要比较 CIDR,请使用in
运算符;例如,ip.src in {1.2.3.0/24}
。 - 在 Wireshark 中,
ssl
是一个协议字段,包含各种类型的数百个其他字段,可用于在多个方面进行比较。 不过,在自定义规则中,ssl
是一个单一的布尔字段,用于确定从客户端到 CIS 的连接是否经过加密。 - 不支持
slice
运算符。 - 并非所有函数都受支持。 目前,
len()
和count()
不支持。