Tune Google Cloud Armor preconfigured WAF rules

Google Cloud Armor provides preconfigured WAF rules, each consisting of multiple signatures sourced from the ModSecurity Core Rule Set (CRS). Each signature corresponds to an attack detection rule in the ruleset. Incoming requests are evaluated against the preconfigured WAF rules. A request matches a preconfigured WAF rule if the request matches any of the signatures that are associated with the preconfigured WAF rule. A match is made when the evaluatePreconfiguredWaf() or evaluatePreconfiguredExpr() expression returns the value true.

Choose a sensitivity level

Each signature has a sensitivity level that corresponds to a ModSecurity paranoia level. You can select a sensitivity between 0 and 4, though sensitivity level 0 means that no rules are enabled by default.

A lower sensitivity level indicates higher confidence signatures, which are less likely to generate a false positive. A higher sensitivity level increases security, but also increases the risk of generating a false positive. When you select a sensitivity level for your WAF rule, you opt in signatures at the sensitivity levels less than or equal to the selected sensitivity level. In the following example, you tune a preconfigured WAF rule by selecting the sensitivity level of 1:

evaluatePreconfiguredWaf('sqli-v33-stable', {'sensitivity': 1})

Opt out rule signatures

If you decide that a preconfigured WAF rule matches more requests than is necessary, or if the rule is blocking traffic that needs to be allowed, the rule can be tuned to disable noisy or otherwise unnecessary signatures. To disable signatures in a particular preconfigured WAF rule, you provide a list of IDs of the unwanted signatures to the evaluatePreconfiguredWaf() expression.

The following example excludes two CRS rule IDs from the preconfigured sqli-v33-stable (CRS 3.3) WAF rule:

evaluatePreconfiguredWaf('sqli-v33-stable', {'sensitivity': 4, 'opt_out_rule_ids': ['owasp-crs-v030301-id942350-sqli', 'owasp-crs-v030301-id942360-sqli']})

When you opt out signature IDs from preconfigured CRS rule sets, you must match the signature ID version with the rule set version (CRS 3.0 or 3.3) to avoid configuration errors.

You can also disable signature IDs by using the legacy expression evaluatePreconfigureExpr(). For more information about preconfigured WAF rule expressions, see the custom rules language reference.

Opt in rule signatures

Instead of opting out rule signatures, you can opt in rule signatures in otherwise disabled sensitivity levels. We recommend that you opt in rule signatures when there are fewer signatures that you want to use in a given sensitivity level than there are rules that you want to opt out. To opt in rule signatures, the sensitivity level must be 0. The following example opts out all cve-canary signatures at all sensitivity levels, and then explicitly opts in owasp-crs-v030001-id044228-cve and owasp-crs-v030001-id144228-cve:

evaluatePreconfiguredWaf('cve-canary', {'sensitivity': 0, 'opt_in_rule_ids': ['owasp-crs-v030001-id044228-cve', 'owasp-crs-v030001-id144228-cve']})

Exclude request fields from inspection

Your custom application might contain content in request fields (like headers, cookies, query parameters, or URIs) that matches signatures in preconfigured WAF rules, but which you know is legitimate. In this case, you can reduce false positives by excluding those request fields from inspection by associating a list of exclusions for request fields with the security policy rule.

When configuring a request field exclusion, you associate it with a target, which can be an entire preconfigured WAF rule, or a list of signatures under a preconfigured WAF rule. You can specify an exact match or a partial match by using a field operator and a field value. The available field operators are as follows:

  • EQUALS: The operator matches if the field value equals the specified value.
  • STARTS_WITH: The operator matches if the field value starts with the specified value.
  • ENDS_WITH: The operator matches if the field value ends with the specified value.
  • CONTAINS: The operator matches if the field value contains the specified value.
  • EQUALS_ANY: The operator matches if the field value is any value.

The following sections provide more information about the request fields that you can exclude from inspection, followed by examples.

Request headers

A list of request header names whose value is excluded from inspection during preconfigured WAF rule evaluation.

The exclusion is only applicable for signatures in the target that would inspect the request header value originally. This includes signatures that are associated with the following request flag in the ModSecurity Core Rule Set:

  • REQUEST_HEADERS

Only the value of the specified request headers are excluded from inspection. The name is still inspected.

Request cookies

A list of request cookie names whose value is excluded from inspection during preconfigured WAF rule evaluation.

The exclusion is only applicable for signatures in the target that would inspect the request cookie value originally. This includes signatures that are associated with the following request flag in the ModSecurity Core Rule Set:

  • REQUEST_COOKIES

Only the value of the specified request cookies are excluded from inspection. The name is still inspected.

Request query parameters

A list of request query parameter names whose value is excluded from inspection during preconfigured WAF rule evaluation.

The exclusion is only applicable for signatures in the target that would inspect the request parameters originally. This includes signatures that are associated with the following request flags in the ModSecurity Core Rule Set:

  • ARGS
  • ARGS_GET
  • REQUEST_URI
  • REQUEST_URI_RAW
  • REQUEST_LINE

Only the value of the specified query parameters are excluded from inspection, which can be in the query string or the POST body. The name is still inspected.

Because query parameters are part of the URI and the request line, these fields are re-assembled for inspection after excluding the specified query parameters. However, for signatures that inspect the entire request body (like signatures that are associated with the request flag REQUEST_BODY), the exclusion for query parameters is not applied.

For example, if you exclude a query parameter named "args", you might still see a match on a signature that inspects the entire request body if the request has an "args" parameter in the POST body and the value of "args" matches.

Request URI

A list of URIs from the request line excluding the query string data to be excluded from inspection during preconfigured WAF rule evaluation.

The exclusion is only applicable for signatures in the target that would inspect the request URI originally. This includes signatures that are associated with the following request flags in the ModSecurity Core Rule Set:

  • REQUEST_URI
  • REQUEST_URI_RAW
  • REQUEST_LINE
  • REQUEST_FILENAME
  • REQUEST_BASENAME

When excluding any of the preceding fields, the field is excluded entirely from inspection, and no re-assembling is performed.

Field values

You must specify a field value if you use a field operator other than EQUALS_ANY.

For request headers, request cookies, and request query parameters, the permitted character set for field values includes the following characters:

  • !, #, $, %, &, *, +, -, ., ^, _, `, |, ~
  • Alpha characters A through Z (both lower and upper cases)
  • Digit characters 0 through 9

When applying exclusions for these request fields, the configured field values are compared as they are against the values (case-insensitive, after transformation) from the request. You are not expected to perform additional encoding if you want to exclude a specific character that's not in the permitted character set.

For request URIs, the field value must be given in a URI format as follows:

  • A scheme is allowed, but is restricted to http or https only.
  • A host is allowed, and can be an IP address.
  • A port is allowed.
  • A path is allowed.
  • A query is not allowed.
  • A fragment is not allowed.

When applying exclusions for request URIs, the configured field values are compared as they are against the URIs (case-insensitive, after transformation) from the request line, excluding the query string. The URIs from the request line can be relative or absolute. Consider this when configuring exclusions for request URIs.

Examples

The first example updates the rule in the security policy POLICY_1 at PRIORITY to add an exclusion configuration for all signatures under the sqli-v33-stable WAF rule, to exclude all request cookies from inspection:

gcloud compute security-policies rules add-preconfig-waf-exclusion PRIORITY \
    --security-policy POLICY_1 \
    --target-rule-set "sqli-v33-stable" \
    --request-cookie-to-exclude "op=EQUALS_ANY"

The second example updates the rule in the security policy POLICY_2 at PRIORITY to add an exclusion configuration for signatures owasp-crs-v030301-id941140-xss and owasp-crs-v030301-id941270-xss under the xss-v33-stable WAF rule, to exclude request headers that either start with abc or end with xyz from inspection:

gcloud compute security-policies rules add-preconfig-waf-exclusion PRIORITY \
    --security-policy POLICY_2 \
    --target-rule-set "xss-v33-stable" \
    --target-rule-ids "owasp-crs-v030301-id941140-xss" "owasp-crs-v030301-id941270-xss" \
    --request-header-to-exclude "op=STARTS_WITH,val=abc" \
    --request-header-to-exclude "op=ENDS_WITH,val=xyz"

The third example updates the rule in the security policy POLICY_3 at PRIORITY to remove all the request field exclusions for the rule IDs owasp-crs-v030301-id942110-sqli and owasp-crs-v030301-id942120-sqli under sqli-v33-stable.

gcloud compute security-policies rules remove-preconfig-waf-exclusion PRIORITY \
    --security-policy POLICY_3 \
    --target-rule-set "sqli-v33-stable" \
    --target-rule-ids "owasp-crs-v030301-id942110-sqli,owasp-crs-v030301-id942120-sqli"

Apply parsing on custom Content-Type header values

When Google Cloud Armor evaluates the POST body against preconfigured WAF rules, the Content-Type header indicates the format of the data in the request body. By default, Google Cloud Armor treats the contents of the POST body as one string, all of which is eligible for inspection and matching on your preconfigured WAF rules. However, you can configure more precise parsing if your incoming requests have a different encoding. Google Cloud Armor supports the following encoding types:

  • JSON
  • GraphQL

To configure the list of custom Content-Type header values for which alternative parsing is applied, use the following example. The example updates the security policy POLICY_NAME to enable JSON parsing, and specifies the content types application/json, application/vnd.api+json, application/vnd.collection+json, and application/vnd.hyper+json:

gcloud compute security-policies update POLICY_NAME \
    --json-parsing STANDARD \
    --json-custom-content-types "application/json,application/vnd.api+json,application/vnd.collection+json,application/vnd.hyper+json"

Alternatively, if your security policy is protecting an application that uses GraphQL or receives GraphQL encoded content, you can use the argument STANDARD_WITH_GRAPHQL to parse the POST body content as GraphQL content, as in the following example:

gcloud compute security-policies update POLICY_NAME \
    --json-parsing STANDARD_WITH_GRAPHQL

The inspection of the POST body is limited to the first 8 KB. For more information, see Security policy limitations.

  • If the JSON content is larger than 8 KB, then Google Cloud Armor applies JSON parsing to the first 8KB of content used that is inspected by any preconfigured WAF rules.

  • If the JSON parser returns no result, URI parsing might be attempted. If the URI parser returns no name-value parameters or only partial name-value parameters, the entire or partial string might be treated as the parameter name for the inspection.

What's next