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

6 minute read
2

When I use AWS WAF, I get false positives for SQL injection (SQLi) or cross-site scripting (XSS) on certain HTTP requests. I want to exclude specific URIs from XSS or SQLi inspection for HTTP requests.

Short description

False positives sometimes occur during XSS and SQLi rule inspection for AWS Managed Rules and custom rules. To avoid false positives, exclude specific URI paths from XSS and SQLi inspection. To do this, use nested statements to write a blocking rule with exceptions so that AWS WAF evaluates the request against all the other rules.

Resolution

Example HTTP or HTTPS request

http://www.amazon.com/path/string1?xss=%3Cscript%3E%3Cscript%3E&sql=UNION%20ALL%20SELECT%201

In the preceding request, the URI path is /path/string1. The string that follows the question mark (?) is the query string. In this example, the query string is xss=%3Cscript%3E%3Cscript%3E&sql=UNION%20ALL%20SELECT%201.

Example rules to allow specific URIs from XSS or SQLi inspection

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

Case 1: Use 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 a 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, the URI path, and a cookie for an SQLi injection attack pattern. For more information, see Use-case specific rule groups.

When a request matches these rules, AWS WAF generates the corresponding labels. Then, your custom rule in the WEB ACL can use these AWS managed rule labels to selectively exclude specific requests from matched rule signatures.

To allow specific URIs, complete the following steps:

  1. Keep the following rules from the AWSManagedRulesCommonRuleSet rule group in Count mode:
    CrossSiteScripting_COOKIE
    CrossSiteScripting_QUERYARGUMENTS
    CrossSiteScripting_BODY
    CrossSiteScripting_URIPATH
  2. Create a rule with a block action with exceptions for URI Paths. Configure the rule with a lower priority than the priority of AWSManagedRulesCommonRuleSet. To configure lower priority in the AWS WAF console, place the rule lower in the list. To configure lower priority in JSON, use a larger Priority value.
    The rule uses the following logic: (XSS_URIPATH or XSS_Cookie or XSS_Body or XSS_QueryArguments) AND (NOT allowlisted 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": "/path/string1",
                    "FieldToMatch": {
                      "UriPath": {}
                    },
                    "TextTransformations": [
                      {
                        "Priority": 0,
                        "Type": "NONE"
                      }
                    ],
                    "PositionalConstraint": "CONTAINS"
                  }
                }
              }
            }
          ]
        }
      },
      "Action": {
        "Block": {}
      },
      "VisibilityConfig": {
        "SampledRequestsEnabled": true,
        "CloudWatchMetricsEnabled": true,
        "MetricName": "whitelist-xss"
      }
    }
    Note: In this example, the OrStatement excludes specific URIs from all labels and parts of the web request: body, headers, URI path, and query arguments. This example assumes that you encountered a false positive for the same URI in all parts of the web request. However, you might encounter a false positive in only one part of the web request, such as in query arguments. In this case, it's a security best practice to create a separate rule for only one part of the web request and its matching label. For this separate rule, don't exclude the specific URI path from all parts of the web request.

For AWSManagedRulesSQLiRuleSet, use the same steps, but replace the labels with AWSManagedRulesSQLiRuleSet generated labels.

If you have multiple URIs that you want to exclude from inspection, then use OrStatement within NotStatement. For example, to exclude /path/string1 and /path/string2, use the following NotStatement:

{
  "NotStatement": {
    "Statement": {
      "OrStatement": {
        "Statements": [
          {
            "ByteMatchStatement": {
              "SearchString": "/path/string1",
              "FieldToMatch": {
                "UriPath": {}
              },
              "TextTransformations": [
                {
                  "Priority": 0,
                  "Type": "NONE"
                }
              ],
              "PositionalConstraint": "CONTAINS"
            }
          },
          {
            "ByteMatchStatement": {
              "SearchString": "/path/string2",
              "FieldToMatch": {
                "UriPath": {}
              },
              "TextTransformations": [
                {
                  "Priority": 0,
                  "Type": "NONE"
                }
              ],
               PositionalConstraint": "CONTAINS"
            }
          }
        ]
      }
    }
  }
}

Case 2: Use custom XSS and SQLi rules

The rule uses the following logic:

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

Use the following rule configuration to inspect XSS attack strings for the request, but also selectively exclude 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": "/path/string1",
                "TextTransformations": [
                  {
                    "Type": "NONE",
                    "Priority": 0
                  }
                ]
              }
            }
          }
        }
      ]
    }
  }
}

Follow this procedure when you use SQLi statements.

Note: It's not a best practice to have a rule with higher priority that allows only the URI. This best practice prevents the request with the allowed URI_PATH from evaluation against all the other rules defined in the Web ACL.

Related information

Rule statement basics

Cross-site scripting attack rule statement

SQL injection attack rule statement

AWS OFFICIAL
AWS OFFICIALUpdated 6 months ago
5 Comments

I've been trying to implement this for hours. You use a URL example at the beginning of the article, but then never reference it. I have specific URIs that I want to allow traffic for. Where do I plug them into your code here? My first thought, after two hours and asking a buddy, is to maybe substitute URI_SearchString with the URI, however that looks like it's referencing a field or something based on the formatting.

replied 2 years ago

Thank you for your comment. We'll review and update the Knowledge Center article as needed.

profile pictureAWS
MODERATOR
replied 2 years ago

Hi,

Good day.

Thanks for the article. Those backspaces in the json is a bad idea :).

Regards, Jarrett

replied 8 months ago

Hi,

I can concur, this does not work. It is simply ignored. Please double check that the instructions are correct.

Regards, Jarrett

replied 8 months ago

Thank you for your comment. We'll review and update the Knowledge Center article as needed.

profile pictureAWS
MODERATOR
replied 8 months ago