Waf Charm

Blog

AWS WAF

Part 5: [New AWS WAF] JSON Explanation

【Table of contents】

  1. Introduction
  2. Description
  3. Statements Details (string match)
  4. Statements details (string match: multiple fields specified)
  5. Statements Details (string match condition plus country specification)
  6. RegexPatternSet / IPSet
  7. Conclusion

1. Introduction

AWS released a new version of AWS WAF on Nov 25, 2019. Since the rules can be written in JSON, we explained about how to write them.
Part 1: [new AWS WAF] Summary of changes
Part 2: [new AWS WAF] AWS Management Console Operation (Managed Rules)
Part 3: [new AWS WAF] AWS Management Console Operations (Original Rules)
Part 4: [new AWS WAF] AWS Management Console Operations (Pattern Sets & Rule Groups)
Part 5: [new AWS WAF] JSON Explanation (this blog)

2. Description

This is the general JSON structure of the entire WebACL excluding the rules.

{
    "Name": "TEST ACL", 	#name of the web ACL
    "Id": "XXXXXXXXXXXX", #Issued ID
    "ARN": "XXXXXXX",	#Issued ARN
    "DefaultAction": { 		#Default Action(BLOCK or ALLOW)
        "Block": {} 
        "Allow": {}
    },
    "Description": "TEST", 	#Web ACL description
    "Rules": [ 				#Array of rules
        {
            <Rule #1>
        }, {
            <Rule #2>
        }
    ],
    "VisibilityConfig": { 
        "SampledRequestsEnabled": true,#Sample request 
        "CloudWatchMetricsEnabled": true, #CloudWatch
        "MetricName": "TestMetric"#Metric name
    } 
}

JSON structure of the Rules.

"Rules": [
    {
        "Name": "rule1",	#Rule name
        "Priority": 1, 		#Rule priority
        "Statements": {		#condition
            <Condition>
        },
        "Action": {			#Select one of the actions
            "Block": {} 
            "Allow": {} 
            "Count": {}
        },
        "VisibilityConfig": { 
            "SampledRequestsEnabled": true,#Sample request
            "CloudWatchMetricsEnabled": true,#CloudWatch
            "MetricName": "rule1"#Metric name
        } 
    }
]

3. Statements Details (string match)

There is only one condition that can be specified in the Statement.

"Statements": {
    "ByteMatchStatement": {
        "SearchString": "kensakumoji", 	#Search string
        "FieldToMatch": {		#Select one of the fields
            "SingleHeader": { "Name": "foo" }, 
            "SingleQueryArgument": { "Name": "foo" }, 
            "AllQueryArguments": {},
            "UriPath": {},
            "QueryString": {}, 
            "Body": {}, 
            "Method": {}
        }, 
        "TextTransformations": [			#transformation process
            { "Priority": 1, "Type": "COMPRESS_WHITE_SPACE" },
            { "Priority": 2, "Type": "HTML_ENTITY_DECODE" }
        ],
        "PositionalConstraint": "EXACTLY"	#match condition
    }
}

If you want to specify multiple Statements to match any of the OR conditions, use the "OrStatement" described below. If you want to specify multiple Statements to match all of the AND conditions, use the "AndStatement".

The following is an example of a description that specifies multiple fields and processes when one of the fields contains a string.

4. Statements details (string match: multiple fields specified)

Put OrStatement under Statements and enclose each condition side by side.

"Statements": {
    "OrStatement": {
        "Statements": [
            "ByteMatchStatement": {
                "SearchString": "kensakumoji", 
                "FieldToMatch": {	
                    "UriPath": {},
                }, 
                "TextTransformations": [
                    { "Priority": 1, "Type": "COMPRESS_WHITE_SPACE" },
                    { "Priority": 2, "Type": "HTML_ENTITY_DECODE" }
                ],
                "PositionalConstraint": "EXACTLY"
            }, {
            "ByteMatchStatement": {
                "SearchString": "kensakumoji", 
                "FieldToMatch": {
                    "QueryString": {}, 
                }, 
                "TextTransformations": [
                    { "Priority": 1, "Type": "COMPRESS_WHITE_SPACE" },
                    { "Priority": 2, "Type": "HTML_ENTITY_DECODE" }
                ],
                "PositionalConstraint": "EXACTLY"
            }, {
            "ByteMatchStatement": {
                "SearchString": "kensakumoji", 
                "FieldToMatch": {				
                    "Body": {}, 
                }, 
                "TextTransformations": [
                    { "Priority": 1, "Type": "COMPRESS_WHITE_SPACE" },
                    { "Priority": 2, "Type": "HTML_ENTITY_DECODE" }
                ],
                "PositionalConstraint": "EXACTLY"
            }
        ]
    }
}

5. Statements Details (string match condition plus country specification)

Add the country specification to the string match condition.

"Statements": {
    "AndStatement": {
        "Statements": [
            "ByteMatchStatement": {
                "SearchString": "kensakumoji", 
                "FieldToMatch": {
                    "UriPath": {},
                }, 
                "TextTransformations": [
                    { "Priority": 1, "Type": "COMPRESS_WHITE_SPACE" },
                    { "Priority": 2, "Type": "HTML_ENTITY_DECODE" }
                ],
                "PositionalConstraint": "EXACTLY"
            }, {
            "GeoMatchStatement": { 
                "CountryCodes": [ "US", "CN" ]		#Specified by ISO Country Code
            }
        ]
    }
}

6. RegexPatternSet / IPSet

Although it is also used in AWS WAF Classic, the regular expression creates a RegexPatternSet and applies it as a rule. Also, the IP control that was used in the whitelist and blacklist has been changed to IPSet. Each call is made to an assigned ARN. Let's take a look at each of the descriptions.
Once RegexPatternSet / IPSet is registered, an ARN will be issued. We will use the issued ARN to create a Statement.

Statements Details (RegexPatternSet / IPSet)

・IP address

"Statements": {
    "IPSetReferenceStatement": {
        "ARN": "IPset" 			#Specify by the issued ARN
    }
}

・Regular expression

"Statements": {
    "RegexPatternReferenceStatement": { 
        "ARN": "Regex",			#Specify by the issued ARN
        "FieldToMatch": {			#Select one of the fields
            "SingleHeader": { "Name": "foo" },
            "SingleQueryArgument": { "Name": "foo" },
            "AllQueryArguments": {},
            "UriPath": {},
            "QueryString": {},
            "Body": {}, 
            "Method": {}
        }, 
        "TextTransformations": [
            { "Priority": 1, "Type": "COMPRESS_WHITE_SPACE" },
            { "Priority": 2, "Type": "HTML_ENTITY_DECODE" }
        ] 
    }
}

Creating a Rule Group
As a rule group, it is possible to create a compilation of several rules. Like RegexPatternSet / IPSet, after registering, an ARN is issued to create a Statement. In case of rule groups, OverrideAction can be used to change the entire rule group to COUNT mode. Switching individual rules to COUNT mode is done by ExcludedRules.

Statements Details (Group)

"Statements": {
    "RuleGroupReferenceStatement": {
        "ARN": "TestRuleGroup", 	#Specify by the issued ARN
        "ExcludedRules": [		#Declare rules to exclude
            { "Name": "Rule1" },
            { "Name": "Rule2" }
        ] 
    }
},
"OverrideAction": {				#Switching to group mode
    "None": {}
},

7. Conclusion

The relation between Condition and Filter in AWS WAF Classic has been changed to a single unit called Statement. We were able to create a single rule by logically combining String Match Statement and Country Match Statement. It was more structured and intuitive to create rules than AWS WAF Classic.