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:
- Keep the following rules from the AWSManagedRulesCommonRuleSet rule group in Count mode:
CrossSiteScripting_COOKIE
CrossSiteScripting_QUERYARGUMENTS
CrossSiteScripting_BODY
CrossSiteScripting_URIPATH
- 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