每项 Google Cloud Armor 安全政策规则都有优先级、匹配条件和操作。Google Cloud Armor 会执行与请求匹配的最高优先级规则的操作。优先级低于匹配优先级最高规则的规则不会被评估,即使它们具有相同的匹配条件也是如此。
每条安全政策规则都支持两种类型的匹配条件:
- 基本匹配条件包含 IP 地址列表或 IP 地址范围列表。使用 Google Cloud CLI 创建规则时,可以使用
--src-ip-ranges
标志定义基本匹配条件。 - 高级匹配条件包含一个包含最多五个子表达式的表达式,可匹配传入请求的各种属性。使用 Google Cloud CLI 创建规则时,可以使用
--expression
标志定义高级匹配条件。
本页介绍了高级匹配条件以及 Google Cloud Armor 自定义规则语言,您可以使用该语言在安全政策规则的高级匹配条件中编写表达式。Google Cloud Armor 自定义规则语言是通用表达式语言 (CEL) 的子集。使用 Google Cloud Armor 自定义规则语言编写的表达式需要两个组成部分:
- 属性:要检查的数据
- 操作:如何使用数据
例如,以下表达式在操作 inIpRange()
中使用属性 origin.ip
和 9.9.9.0/24
。在这种情况下,如果 origin.ip
在 9.9.9.0/24
IP 地址范围内,则表达式返回 true。
inIpRange(origin.ip, '9.9.9.0/24')
尽管上例表达式仅匹配源 IP 地址,但如果您在 Google Cloud Armor 安全政策规则中使用该示例表达式,则该规则在配额方面会被视为具有高级匹配条件的规则。如需了解详情,请参阅 Google Cloud Armor 配额和限制。
属性
属性表示来自传入请求的信息,例如源 IP 地址或请求的网址路径。
字段 | 类型 | 字段说明 |
---|---|---|
origin.ip |
字符串 | 请求的源 IP 地址。 |
origin.user_ip |
字符串 | 来源客户端的 IP 地址,由上游代理添加在 HTTP-HEADER 中。在使用此属性之前,您必须在安全政策的 advancedOptionsConfig 字段中配置 userIpRequestHeaders[] 选项,以匹配 True-Client-IP 、X-Forwarded-For 或 X-Real-IP 等来源。
如果未配置 |
origin.tls_ja3_fingerprint |
字符串 | JA3 TLS/SSL 指纹(如果客户端使用 HTTPS 、HTTP/2 或 HTTP/3 进行连接)。如果不可用,则返回空字符串。 |
request.headers |
地图 | HTTP 请求标头的字符串到字符串映射。如果标头包含多个值,则此映射中的值将是标头所有值的英文逗号分隔字符串。此映射中的键全部为小写。系统会检查外部应用负载均衡器接受的所有标头,并应用相同的标头限制。 建议先使用 |
request.method |
字符串 | HTTP 请求方法,例如 GET 或 POST 。 |
request.path |
字符串 | 所请求的 HTTP 网址路径。 |
request.scheme |
字符串 | HTTP 网址架构,例如 http 或 https 。此属性的值均为小写。 |
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 地址前缀的网络运营商确定。 |
reCAPTCHA 属性
本部分列出了仅适用于 reCAPTCHA 令牌或豁免 Cookie 的特性。如果要评估的 reCAPTCHA 令牌或豁免 Cookie 因以下某种原因而不可用或无效,则基于这些属性的子表达式会返回 false
:
- 令牌格式错误,无法解码。
- 令牌包含无效的属性。例如,令牌是使用与规则的关联 reCAPTCHA 密钥不匹配的 reCAPTCHA 密钥生成的。
- 令牌已过期。
豁免 Cookie 特性
字段 | 类型 | 字段说明 |
---|---|---|
token.recaptcha_exemption.valid |
bool |
是否存在有效的 reCAPTCHA 豁免 Cookie。 |
操作令牌特性
字段 | 类型 | 字段说明 |
---|---|---|
token.recaptcha_action.score |
float |
reCAPTCHA 操作令牌中的分数。有效分数的范围为 0.0 到 1.0 ,其中 0.0 表示很可能是非法用户,1.0 表示很可能是合法用户。 |
token.recaptcha_action.captcha_status |
string |
reCAPTCHA 操作令牌中的人机识别系统状态。有效状态为 NONE 、PASS 或 FAIL ,其中 NONE 表示 reCAPTCHA 评估期间未涉及任何验证,因此操作令牌中缺少人机识别系统字段。 |
token.recaptcha_action.action |
string |
reCAPTCHA 操作令牌中的操作名称(最多 100 个字符)。请参阅操作名称。 |
token.recaptcha_action.valid |
bool |
是否存在有效的 reCAPTCHA 操作令牌。 |
会话令牌特性
字段 | 类型 | 字段说明 |
---|---|---|
token.recaptcha_session.score |
float |
reCAPTCHA 会话令牌的分数。有效分数的范围为 0.0 到 1.0 ,其中 0.0 表示很可能是非法用户,1.0 表示很可能是合法用户。 |
token.recaptcha_session.valid |
bool |
是否存在有效的 reCAPTCHA 会话令牌。 |
运维
以下参考信息描述了可与属性(由 x
、y
和 k
表示)搭配使用来定义规则表达式的运算符。
表达式 | 说明 |
---|---|
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。 |
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 类型。接着可以将其用于使用标准算术运算符(例 > 和 <= 等)进行整数比较。这仅适用于应该为整数的值。 |
size(x) |
返回字符串 x 的长度。 |
x.urlDecode() |
返回 x 的网址解码值;%## 格式的字符序列会被替换为非 ASCII 等效字符,而 + 则被替换为空格。无效编码会按原样返回。 |
x.urlDecodeUni() |
返回 x 的网址解码值;除了 urlDecode() 之外,还会处理 %u### 格式的 Unicode 字符序列。无效编码会按原样返回。 |
x.utf8ToUnicode() |
返回 UTF-8 编码 x 的小写 Unicode 表示形式。 |
表达式示例
对于这些表达式中的每一个,所采取的操作取决于该表达式是包含在拒绝规则还是允许规则中。
根据 IPv4 或 IPv6 的 IP 地址范围允许或拒绝访问
以下表达式与来自
198.51.100.0/24
IP 地址范围的请求匹配:inIpRange(origin.ip, '198.51.100.0/24')
以下表达式与来自
2001:db8::/32
IP 地址范围的请求匹配:inIpRange(origin.ip, '2001:db8::/32')
根据上游代理后面的自定义客户端 IP 地址范围允许或拒绝访问
如果您已配置 origin.user_ip
运算符,则可以根据在 advancedOptionsConfig.userIpRequestHeaders[]
字段中指定的标头值进行匹配。
以下表达式与源自
192.0.2.0/24
IP 地址范围的请求匹配:inIpRange(origin.user_ip, '192.0.2.0/24')
以下表达式与源自
2001:db8::/32
IP 地址范围的请求匹配:inIpRange(origin.user_ip, '2001:db8::/32')
使用特定 Cookie 允许或拒绝流量
以下表达式与具有包含
80=BLAH
的 Cookie 的请求匹配:has(request.headers['cookie']) && request.headers['cookie'].contains('80=BLAH')
使用非空 referer
标头允许或拒绝流量
以下表达式与具有非空
referer
标头的请求匹配:has(request.headers['referer']) && request.headers['referer'] != ""
根据标头中的主机网址允许或拒绝流量
以下表达式与对特定网址的请求匹配:
request.headers['host'].lower().contains('test.example.com')
允许或拒绝来自特定区域的流量
如果您的 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 中包含字符串
example_path
的请求匹配:request.path.matches('/example_path/')
以下表达式与
User-Agent
标头字段中包含Chrome
的请求匹配:request.headers['user-agent'].matches('Chrome')
以下表达式显示了包含
wordpress
的User-Agent
标头的不区分大小写的匹配;它与User-Agent:WordPress/605.1.15
、User-Agent:wordPress
以及wordpress
的其他变体匹配:request.headers['user-agent'].matches('(?i:wordpress)')
允许或拒绝包含特定 base64 解码值的流量
以下表达式与
user-id
标头的 base64 解码值为myValue
的请求匹配:has(request.headers['user-id']) && request.headers['user-id'].base64Decode().contains('myValue')
允许或拒绝包含特定长度的字符串值的流量
以下表达式与网址长度超过 10 个字符的请求匹配:
size(request.path) > 10
以下表达式与标头
x-data
长度大于或等于 1024 个字符的请求匹配:size(request.headers['x-data']) >= 1024
允许或拒绝 HTTP 正文中 content-length
为零的流量
以下表达式与 HTTP 正文中
content-length
为零的请求匹配:int(request.headers["content-length"]) == 0
允许或拒绝包含特定网址编码值的流量
以下表达式与 Cookie 值包含
%3c
的请求匹配:has(request.headers['cookie']) && request.headers['cookie'].urlDecode().contains('<')
允许或拒绝包含 Unicode 字符串的特定网址编码值的流量
以下表达式与 Cookie 值等于
Match%2BValue
或Match%u002BValue
的请求匹配:has(request.headers['cookie']) && request.headers['cookie'].urlDecodeUni() == 'Match+Value'
允许或拒绝包含 UTF-8 文本的特定 Unicode 字符串的流量
以下表达式与 Cookie 值等于
¬
的请求匹配:has(request.headers['cookie']) && request.headers['cookie'].utf8ToUnicode() == '%u00ac'
根据已知的 JA3 指纹允许或拒绝流量
以下表达式与 JA3 指纹等于
e7d705a3286e19ea42f587b344ee6865
的请求匹配:origin.tls_ja3_fingerprint == 'e7d705a3286e19ea42f587b344ee6865'
根据 JA3 指纹列表允许或拒绝流量
以下表达式与 JA3 指纹等于以下任一 JA3 指纹的请求匹配:
e7d705a3286e19ea42f587b344ee6865
f8a5929f8949e846267b582072e35f84
8f8b62163873a62234c14f15e7b88340
origin.tls_ja3_fingerprint == 'e7d705a3286e19ea42f587b344ee6865' || origin.tls_ja3_fingerprint == 'f8a5929f8949e846267b582072e35f84' || origin.tls_ja3_fingerprint == '8f8b62163873a62234c14f15e7b88340'
预配置的 WAF 规则
预配置的 WAF 规则使用预配置的静态签名、正则表达式或两者,以匹配 HTTP POST 正文、HTTP 请求标头和查询参数。可用的预配置 WAF 规则基于 OWASP Modsecurity 核心规则集 3.3 版。Google Cloud Armor 提供了多种预定义的预配置 WAF 规则。如需查看预配置的 WAF 规则的完整列表,请参阅 Google Cloud Armor 的预配置 WAF 规则概览。
如需列出所有可用的预配置 WAF 规则,请参阅列出可用的预配置 WAF 规则。
如需详细了解预配置的 WAF 规则,请参阅使用场景使用预配置的 WAF 规则缓解应用层攻击。
预配置的 WAF 规则名称
预配置的 WAF 规则名称的格式为 <attack category>-<ModSecurity CRS version>-<version field>
。攻击类别指定要防御的攻击类型,例如 xss
(跨站脚本攻击)或 sqli
(SQL 注入攻击)。
支持的版本字段为 stable
和 canary
。对规则的添加和修改首先在 canary
版本中发布。在添加和修改被认为是安全稳定时,则会将它们升级为 stable
版本。
预配置的 WAF 规则成员 ID
预配置的 WAF 规则包含多个表达式,每个表达式都有自己的签名。例如,预配置的 WAF 规则 xss-v33-stable
包含一个名为 owasp-crs-v030301-id941100-xss
的表达式,它对应于版本 3.3 的规则 ID id941100
。您可以使用签名来排除使用特定的表达式,如果特定的表达式始终触发假正例,这将非常有用。如需了解详情,请参阅假正例问题排查信息。
如需了解核心规则集以及在不同敏感度级层下的调整,请参阅调整 Google Cloud Armor WAF 规则。
预配置的 WAF 规则的运算符
表达式 | 说明 |
---|---|
evaluatePreconfiguredWaf(string, MAP<string, dyn>) |
如果指定 WAF 规则集中的任一 WAF 签名返回 true,则返回 true。第一个参数是 WAF 规则集的名称,例如 xss-v33-stable 。第二个参数(可选)是一个映射,其中键是一个字符串,值是根据键动态输入的。此参数的目的是微调所评估的 WAF 签名。接受的键包括:
键“opt_out_rule_ids”和“opt_in_rule_ids”相互排斥。如果您想查看并手动选择启用后续添加到现有规则集的新 WAF 签名,可以选择使用“opt_in_rule_ids”。 |
evaluatePreconfiguredExpr(string, LIST) |
如果指定的预配置 WAF 规则中的任何一个表达式返回 true,则返回 true。 第一个参数是预配置的 WAF 规则的名称,例如 |
预配置的 WAF 规则示例
以下表达式使用
xss-v33-stable
预配置的 WAF 规则来缓解 XSS 攻击:evaluatePreconfiguredExpr('xss-v33-stable')
以下表达式使用
xss-v33-stable
预配置的 WAF 规则中的所有表达式,但成员 ID941100
和941110
除外:evaluatePreconfiguredExpr('xss-v33-stable', ['owasp-crs-v030301-id941100-xss', 'owasp-crs-v030301-id941110-xss'])
以下表达式使用预配置的 WAF 规则来缓解来自
198.51.100.0/24
IP 地址范围的 SQLi 攻击:inIpRange(origin.ip, '198.51.100.0/24') && evaluatePreconfiguredExpr('sqli-v33-stable')