Tune Google Cloud Armor preconfigured WAF rules

Stay organized with collections Save and categorize content based on your preferences.

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 xss-v33-stable (CRS 3.3) WAF rule:

evaluatePreconfiguredWaf('xss-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 (case-insensitive, after transformation) 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 (case-insensitive, after transformation) 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 (case-insensitive, after transformation) 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 (case-insensitive, after transformation) 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.

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 beta 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 beta 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 beta 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 JSON parsing on custom Content-Type header values

When evaluating POST body against preconfigured WAF rules, the Content-Type header indicates the format of the data in the request body. By default, JSON parsing is only applied when JSON parsing is enabled and the Content-Type header is set to application/json. However, you can configure a list of custom Content-Type header values for which to apply JSON parsing. The following 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"

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

  • If the JSON content is larger than 8 KB, such that the JSON parser returns a partial list of name-value parameters, the results parsed thus far are used for the parameter inspection.

  • 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