Google Cloud Armor 自定义规则语言参考文档

利用 Google Cloud Armor,您可以在安全政策中使用可配置的匹配条件和操作来定义优先规则。规则生效,这意味着如果规则是最高优先级规则,且其条件与传入请求的特性匹配,则系统会应用配置的操作。

匹配条件有两种:

  • 基本匹配条件包含 IP 地址列表或 IP 地址范围列表。
  • 高级匹配条件包含一个具有多个子表达式的表达式,以匹配传入请求的各种属性。

自定义规则语言用于在安全政策规则的高级匹配条件下编写表达式。Google Cloud Armor 自定义规则语言是通用表达式语言 (CEL) 的扩展。

表达式需要两个组成部分:

  • 可以在规则表达式中检查的属性。
  • 可以作为表达式的一部分对属性执行的操作。

例如,以下表达式在操作 inIpRange() 中使用属性 origin.ip9.9.9.0/24。在这种情况下,如果 origin.ip9.9.9.0/24 IP 地址范围内,则表达式返回 true。

inIpRange(origin.ip, '9.9.9.0/24')

特性

属性表示来自传入请求的信息,例如源 IP 地址或请求的网址路径。

字段 类型 字段说明
origin.ip 字符串 请求的源 IP 地址。
request.headers 映射 HTTP 请求标头的字符串到字符串映射。如果标头包含多个值,则此映射中的值将是标头所有值的英文逗号分隔字符串。此映射中的键全部为小写。每个标头值仅前 16 KB 可用于检查。根据 Google Cloud 负载平衡器规范,任何超过 16 KB 的标头值都将被截断。
request.method 字符串 HTTP 请求方法,例如 GETPOST
request.path 字符串 所请求的 HTTP 网址路径。
request.scheme 字符串 HTTP 网址架构,例如 httphttps。此属性的值均为小写
request.query 字符串 HTTP 网址查询,格式为 name1=value&name2=value2,显示在 HTTP 请求的第一行中。未执行解码。
origin.region_code 字符串 与原始 IP 相关联的 Unicode 国家/地区代码,例如 US。如果您要创建使用 ISO 3166-1 alpha 2 国家或地区代码的规则或表达式,请注意 Google Cloud Armor 会独立处理每个代码。Google Cloud Armor 规则和表达式显式使用这些地区代码来允许或拒绝请求。

如需了解详情,请参阅 Unicode 技术标准中的 unicode_region_subtag

origin.asn 字符串 与源 IP 地址关联的自治系统编号 (ASN)。 全局唯一 ASN 基于支持来源 IP 地址的 IP 地址前缀的网络运营商确定。

运维

以下参考信息描述了可与属性(由 xyk 表示)搭配使用来定义规则表达式的运算符。

表达式 说明
x == "foo" 如果 x 等于指定常量字符串字面量,则返回 true。
x == R"fo'o" 如果 x 等于不解释转义序列的指定原始字符串字面量,则返回 true。原始字符串字面量便于表示自己必须使用转义序列字符的字符串。
x == y 如果 x 等于 y,则返回 true。
x != y 如果 x 不等于 y,则返回 true。
x + y 返回串联的字符串 xy。
x && y 如果 x 和 y 均为 true,则返回 true。
x || y 如果 x、y 或两者均为 true,则返回 true。
!x 如果布尔值 x 为 false,则返回 true;如果布尔值 x 为 true,则返回 false。
x.contains(y) 如果字符串 x 包含子字符串 y,则返回 true。
x.startsWith(y) 如果字符串 x 以子字符串 y 开头,则返回 true。
x.endsWith(y) 如果字符串 x 以子字符串 y 结尾,则返回 true。
x.matches(y) 如果字符串 x 与指定的 RE2 模式 y 匹配,则返回 true。RE2 模式是使用停用 Unicode 功能的 RE2::Latin1 选项编译的。
inIpRange(x, y) 如果 IP 地址 x 包含在 IP 范围 y 内,则返回 true。IPv6 地址的子网掩码不能大于 /64。
x.lower() 返回字符串 x 的小写值。
x.upper() 返回字符串 x 的大写值。
x.base64Decode() 返回 x 的 base64 解码值;字符 _ - 首先被相应替换为 / +。如果 x 不是有效的 base64 值,则返回 ""(空字符串)。
has(m['k']) 如果键 'k' 在映射 'm' 中可用,则返回 true。
m['k'] 如果 'k' 可用,则返回字符串到字符串映射 m 中的键 k 处的值,否则返回错误。建议先使用 "has(m['k'])==true" 检查可用性。
int(x) 将字符串结果 x 转换为 int 类型。接着可以将其用于使用标准算术运算符(例 > 和 <= 等)进行整数比较。这仅适用于应该为整数的值。

表达式示例

对于这些表达式中的每一个,所采取的操作取决于该表达式是包含在拒绝规则还是允许规则中。

根据 IPv4 或 IPv6 的 IP 地址范围允许或拒绝访问

  • 以下表达式与来自 9.9.9.0/24 IP 地址范围的请求匹配:

    inIpRange(origin.ip, '9.9.9.0/24')
    
  • 以下表达式与来自 2001:db8::/32 IP 地址范围的请求匹配:

    inIpRange(origin.ip, '2001:db8::/32')
    
  • 以下表达式与具有包含 80=BLAH 的 Cookie 的请求匹配:

    has(request.headers['cookie']) && request.headers['cookie'].contains('80=BLAH')
    

使用非空 referer 标头允许或拒绝流量

  • 以下表达式与具有非空 referer 标头的请求匹配:

    has(request.headers['referer']) && request.headers['referer'] != ""
    

允许或拒绝来自特定区域的流量

如果您的 Web 应用在 AU 区域尚不可用,则必须阻止来自该区域的所有请求。

  • 在拒绝规则中,使用以下表达式,该表达式与来自 AU 区域的请求匹配:

    origin.region_code == 'AU'
    

或者,如果 Web 应用仅AU 区域中可用,则来自所有其他区域的请求必须被阻止。

  • 在拒绝规则中,使用以下表达式,该表达式匹配来自 AU 区域以外的所有区域的请求:

    origin.region_code != 'AU'
    

地区代码基于 ISO 3166-1 alpha 2 代码。在某些情况下,一个地区对应一个国家/地区,但并非总是如此。例如,US 代码包括美国各州、一个特区和六个美国本土外地区。

允许或拒绝来自特定 ASN 的流量

如果 Web 应用需要由特定网络运营商提供服务的客户使用,您可以使用网络运营商的 ASN 编号来屏蔽。

  • 在拒绝规则中,使用以下表达式来匹配来自特定 ASN 的请求:

    origin.asn == 123
    

或者,如果您的 Web 应用仅可供特定网络运营商的用户使用,则必须阻止来自所有其他网络运营商的请求。

  • 在拒绝规则中,使用以下表达式,该表达式与您不想允许的运算符以外的所有其他运算符相匹配。

    origin.asn != 123
    

多个表达式

如需在单条规则中添加多个条件,请组合多个子表达式。

  • 在以下示例中,来自 AU 地区中的 1.2.3.0/24(例如您的 Alpha 版测试人员)的请求与以下表达式匹配:

    origin.region_code == "AU" && inIpRange(origin.ip, '1.2.3.0/24')
    
  • 以下表达式与来自 1.2.3.4 的请求匹配,其中用户代理包含字符串 WordPress

    inIpRange(origin.ip, '1.2.3.4/32') &&
    has(request.headers['user-agent']) && request.headers['user-agent'].contains('WordPress')
    

允许或拒绝与正则表达式匹配的请求 URI 的流量

  • 以下表达式与 URI 中包含字符串 bad_path 的请求匹配:

    request.path.matches('/bad_path/')
    
  • 以下表达式与 User-Agent 标头字段中包含 Chrome 的请求匹配:

    request.headers['user-agent'].matches('Chrome')
    
  • 以下表达式显示了包含 wordpressUser-Agent 标头的不区分大小写的匹配;它与 User-Agent:WordPress/605.1.15User-Agent:wordPress 以及 wordpress 的其他变体匹配:

    request.headers['user-agent'].matches('(?i:wordpress)')
    

允许或拒绝包含特定 Base64 解码值的流量

  • 以下表达式与具有 user-id 标头的 myValue Base64 解码值的请求匹配:

    has(request.headers['user-id']) && request.headers['user-id'].base64Decode().contains('myValue')
    

允许或拒绝 HTTP 正文中 content-length 为零的流量

  • 以下表达式与 HTTP 正文中 content-length 为零的请求匹配:

    int(request.headers["content-length"]) == 0
    

预配置的规则

预配置的规则使用预配置的静态签名、正则表达式或两者,以匹配 HTTP 请求标头和查询参数。可用的预配置规则基于 OWASP Modsecurity 核心规则集 3.0.2 版。Google Cloud Armor 提供以下预定义的表达式集:

  • xss-<version>:防范跨站脚本攻击
  • sqli-<version>:防范 SQL 注入攻击
  • lfi-<version>:防范本地文件包含攻击
  • rfi-<version>:防御远程文件包含攻击
  • rce-<version>:防御远程代码执行攻击

如需列出所有可用的预配置规则,请参阅列出可用的预配置规则

如需详细了解预配置规则,请参阅使用场景使用预配置规则缓解应用层攻击

表达式集名称

表达式集名称的格式为 <attack category>-<version field>。攻击类别指定要防御的攻击类型,例如 xss(跨站脚本攻击)或 sqli(SQL 注入攻击)。

支持的版本字段为 stablecanary。对规则的添加和修改首先在 canary 版本中发布。在添加和修改被认为是安全稳定时,则会将它们升级为 stable 版本。

表达式集成员 ID

表达式集包含多个表达式,每个表达式都有自己的核心规则集 (CRS) ID。例如,表达式集 xss-stable 包括一个名为 owasp-crs-v020901-id981136-xss 的表达式,它对应于 version 2.9.1 的规则 ID 981136。您可以使用 CRS ID 来排除使用特定的表达式,如果特定的表达式始终触发假正例,这将非常有用。如需了解详情,请参阅假正例问题排查信息。

如需了解核心规则集以及在不同敏感度级层下的调整,请参阅调整 Google Cloud Armor WAF 规则

预配置规则的运算符

表达式 说明
evaluatePreconfiguredExpr(string, LIST)

如果指定表达式集中的任何一个表达式返回 true,则返回 true。

第一个参数是表达式集的名称,例如 xss-stable。第二个参数(可选)是应从评估中排除的 ID 的英文逗号分隔字符串列表。当表达式集的指定成员触发假正例时,排除列表很有用。

预配置规则示例

  • 以下表达式使用 xss-stable 预配置规则来缓解 XSS 攻击:

    evaluatePreconfiguredExpr('xss-stable')
    
  • 以下表达式使用 xss-stable 预配置规则中的所有表达式,但成员 ID 981136981138 除外:

    evaluatePreconfiguredExpr('xss-stable', ['owasp-crs-v020901-id981136-xss',
    'owasp-crs-v020901-id981138-xss'])
    
  • 以下表达式使用预配置规则来缓解来自 198.51.100.0/24 IP 地址范围的 SQLi 攻击:

    inIpRange(origin.ip, '198.51.100.0/24') && evaluatePreconfiguredExpr('sqli-stable')
    

后续步骤