How do I exclude specific URIs from XSS or SQLi inspection for HTTP requests when using AWS WAF?

Last updated: 2022-07-21

I'm receiving false positives for SQL injection (SQLi) or cross-site scripting (XSS) on certain HTTP requests.  How do I exclude specific URIs from XSS or SQLi inspection for HTTP requests when using AWS WAF?

Short description

False positives sometimes occur during XSS and SQLi rule inspection for AWS Managed Rules and custom rules. You can exclude specific URI paths from XSS and SQLi inspection to avoid false positives. To do this, use nested statements to write the allow rule so that the request is evaluated against all the other rules.

Resolution

Example HTTP or HTTPS request

http://www.amazon.com/path/string1?abc=123&xyz=567

In the preceding request, the URI path is '/path/string1'. Any string following '?' is called the query string, such as ' abc=123&xyz=567' in the preceding example. In the query string, 'abc' and 'xyz' are the query parameters with values '123' and '567', respectively.

Example rules for allowing specific URIs from XSS or SQLi inspection

Note: The following example rule configurations are for reference only. You must customize these rules for PositionalConstraint, SearchString, TextTransformations, and so on. You can use similar logic to allow specific headers, query parameters, and so on.

Case 1: Using AWS Managed Rules

The AWS managed rule group AWSManagedRulesCommonRuleSet contains the following rules:

  • CrossSiteScripting_COOKIE
  • CrossSiteScripting_QUERYARGUMENTS
  • CrossSiteScripting_BODY
  • CrossSiteScripting_URIPATH

The AWSManagedRulesCommonRuleSet rule group has BLOCK action that inspects for an XSS attack string in the corresponding part of the request. For more information, see Core rule set (CRS) managed rule group.

Similarly, the rule group AWSManagedRulesSQLiRuleSet has rules to inspect query parameters, the body, and a cookie for an SQLi Injection attack pattern. For more information, see Use-case specific rule groups.

When a request matches the preceding rules, AWS WAF generates the corresponding labels. The labels are used in the rule defined later in the Web ACL to selectively exclude specific requests (based on URI, in this example).

To allow specific URIs, do the following:

1.    Keep the following rules from the AWSManagedRulesCommonRuleSet rule group in Count mode:

  • CrossSiteScripting_COOKIE
  • CrossSiteScripting_QUERYARGUMENTS
  • CrossSiteScripting_BODY
  • CrossSiteScripting_URIPATH

2.    Create an allow rule configured with lower priority than that of AWSManagedRulesCommonRuleSet.

The logic of the rule is as follows:

(XSS_URIPATH or XSS_Cookie or XSS_Body or XSS_QueryArguments) AND (NOT whitelisted URIString) = BLOCK

Use the following configuration:

{
  "Name": "whitelist-xss",
  "Priority": 10,
  "Statement": {
    "AndStatement": {
      "Statements": [
        {
          "OrStatement": {
            "Statements": [
              {
                "LabelMatchStatement": {
                  "Scope": "LABEL",
                  "Key": "awswaf:managed:aws:core-rule-set:CrossSiteScripting_URIPath"
                }
              },
              {
                "LabelMatchStatement": {
                  "Scope": "LABEL",
                  "Key": "awswaf:managed:aws:core-rule-set:CrossSiteScripting_Cookie"
                }
              },
              {
                "LabelMatchStatement": {
                  "Scope": "LABEL",
                  "Key": "awswaf:managed:aws:core-rule-set:CrossSiteScripting_Body"
                }
              },
              {
                "LabelMatchStatement": {
                  "Scope": "LABEL",
                  "Key": "awswaf:managed:aws:core-rule-set:CrossSiteScripting_QueryArguments"
                }
              }
            ]
          }
        },
        {
          "NotStatement": {
            "Statement": {
              "ByteMatchStatement": {
                "SearchString": "URI_SearchString",
                "FieldToMatch": {
                  "UriPath": {}
                },
                "TextTransformations": [
                  {
                    "Priority": 0,
                    "Type": "NONE"
                  }
                ],
                "PositionalConstraint": "CONTAINS"
              }
            }
          }
        }
      ]
    }
  },
  "Action": {
    "Block": {}
  },
  "VisibilityConfig": {
    "SampledRequestsEnabled": true,
    "CloudWatchMetricsEnabled": true,
    "MetricName": "whitelist-xss"
  }
}

Follow the preceding steps for AWSManagedRulesSQLiRuleSet by replacing the labels with AWSManagedRulesSQLiRuleSet generated labels.

Case 2: Using custom XSS and SQLi rules

The logic of the rule is as follows:

(XSS_URIPATH or XSS_Cookie or XSS_Body or XSS_QueryArguments) AND (NOT whitelisted URIString) = BLOCK

Use the following configuration for the rule to inspect XSS attack strings for the request while selectively excluding a specific URI_PATH:

{
  "Name": "xss-URI",
  "Priority": 10,
  "Action": {
    "Block": {}
  },
  "VisibilityConfig": {
    "SampledRequestsEnabled": true,
    "CloudWatchMetricsEnabled": true,
    "MetricName": "xss-URI"
  },
  "Statement": {
    "AndStatement": {
      "Statements": [
        {
          "OrStatement": {
            "Statements": [
              {
                "XssMatchStatement": {
                  "FieldToMatch": {
                    "UriPath": {}
                  },
                  "TextTransformations": [
                    {
                      "Priority": 0,
                      "Type": "NONE"
                    }
                  ]
                }
              },
              {
                "XssMatchStatement": {
                  "FieldToMatch": {
                    "Cookies": {
                      "MatchPattern": {
                        "All": {}
                      },
                      "MatchScope": "ALL",
                      "OversizeHandling": "CONTINUE"
                    }
                  },
                  "TextTransformations": [
                    {
                      "Priority": 0,
                      "Type": "NONE"
                    }
                  ]
                }
              },
              {
                "XssMatchStatement": {
                  "FieldToMatch": {
                    "Body": {
                      "OversizeHandling": "CONTINUE"
                    }
                  },
                  "TextTransformations": [
                    {
                      "Priority": 0,
                      "Type": "NONE"
                    }
                  ]
                }
              },
              {
                "XssMatchStatement": {
                  "FieldToMatch": {
                    "AllQueryArguments": {}
                  },
                  "TextTransformations": [
                    {
                      "Priority": 0,
                      "Type": "NONE"
                    }
                  ]
                }
              }
            ]
          }
        },
        {
          "NotStatement": {
            "Statement": {
              "ByteMatchStatement": {
                "FieldToMatch": {
                  "UriPath": {}
                },
                "PositionalConstraint": "CONTAINS",
                "SearchString": "URI_SearchString",
                "TextTransformations": [
                  {
                    "Type": "NONE",
                    "Priority": 0
                  }
                ]
              }
            }
          }
        }
      ]
    }
  }
}

Follow the preceding procedure when using SQLi statements.

Note: It's not a best practice to have a rule with higher priority that allows just the URI. Doing this doesn't allow the request with the allowed URI_PATH to be evaluated against all the other rules defined in the Web ACL.