├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── JSON ├── description.txt ├── rule-001.json ├── rule-002.json ├── rule-003.json ├── rule-004.json ├── rule-005.json ├── rule-006.json ├── rule-007.json ├── rule-008.json ├── rule-009.json ├── rule-010.json ├── rule-011.json ├── rule-012.json ├── rule-013.json ├── rule-014.json └── rule-015.json ├── LICENSE ├── README.md └── YAML ├── description.txt ├── snippet-001.yaml ├── webacl-create-001.yaml ├── webacl-create-002.yaml └── webacl-create-003.yaml /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | ## Code of Conduct 2 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 3 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 4 | opensource-codeofconduct@amazon.com with any additional questions or comments. 5 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guidelines 2 | 3 | Thank you for your interest in contributing to our project. Whether it's a bug report, new feature, correction, or additional 4 | documentation, we greatly value feedback and contributions from our community. 5 | 6 | Please read through this document before submitting any issues or pull requests to ensure we have all the necessary 7 | information to effectively respond to your bug report or contribution. 8 | 9 | 10 | ## Reporting Bugs/Feature Requests 11 | 12 | We welcome you to use the GitHub issue tracker to report bugs or suggest features. 13 | 14 | When filing an issue, please check existing open, or recently closed, issues to make sure somebody else hasn't already 15 | reported the issue. Please try to include as much information as you can. Details like these are incredibly useful: 16 | 17 | * A reproducible test case or series of steps 18 | * The version of our code being used 19 | * Any modifications you've made relevant to the bug 20 | * Anything unusual about your environment or deployment 21 | 22 | 23 | ## Contributing via Pull Requests 24 | Contributions via pull requests are much appreciated. Before sending us a pull request, please ensure that: 25 | 26 | 1. You are working against the latest source on the *master* branch. 27 | 2. You check existing open, and recently merged, pull requests to make sure someone else hasn't addressed the problem already. 28 | 3. You open an issue to discuss any significant work - we would hate for your time to be wasted. 29 | 30 | To send us a pull request, please: 31 | 32 | 1. Fork the repository. 33 | 2. Modify the source; please focus on the specific change you are contributing. If you also reformat all the code, it will be hard for us to focus on your change. 34 | 3. Ensure local tests pass. 35 | 4. Commit to your fork using clear commit messages. 36 | 5. Send us a pull request, answering any default questions in the pull request interface. 37 | 6. Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation. 38 | 39 | GitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and 40 | [creating a pull request](https://help.github.com/articles/creating-a-pull-request/). 41 | 42 | 43 | ## Finding contributions to work on 44 | Looking at the existing issues is a great way to find something to contribute on. As our projects, by default, use the default GitHub issue labels (enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at any 'help wanted' issues is a great place to start. 45 | 46 | 47 | ## Code of Conduct 48 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 49 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 50 | opensource-codeofconduct@amazon.com with any additional questions or comments. 51 | 52 | 53 | ## Security issue notifications 54 | If you discover a potential security issue in this project we ask that you notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/). Please do **not** create a public github issue. 55 | 56 | 57 | ## Licensing 58 | 59 | See the [LICENSE](LICENSE) file for our project's licensing. We will ask you to confirm the licensing of your contribution. 60 | 61 | We may ask you to sign a [Contributor License Agreement (CLA)](http://en.wikipedia.org/wiki/Contributor_License_Agreement) for larger changes. 62 | -------------------------------------------------------------------------------- /JSON/description.txt: -------------------------------------------------------------------------------- 1 | 2 | * rule-001.json 3 | Logical Statement: ([String Match 1] OR [String Match 2]) AND [IP Set Match] 4 | Description: Ideal when you need to match request originating from specific IP that also contains certain string patterns within the request. 5 | 6 | * rule-002.json 7 | Logical Statement: ([Regex Match] AND NOT([IP Set Match])) OR [Size Constraint Match] 8 | Description: If request contains certain regex patterns and is not from known list of IPs, or query argument size is equal to 1337, then block the request. 9 | 10 | * rule-003.json 11 | Logical Statement: NOT([IP Set Match]) AND NOT([Regex Match]) AND NOT([String Match]) 12 | Description: Simple AND logical statement with 3 separate NOT conditions. 13 | 14 | * rule-004.json 15 | Logical Statement: 7-way OR [String Match] 16 | Description: Simple OR logical statement with assortment of 7 string matches. 17 | 18 | * rule-005.json 19 | Logical Statement: [Geo Match] AND NOT([Regex Match Set]) 20 | Description: Only block when it's country listed and does not fall into regex pattern specified. 21 | 22 | * rule-006.json 23 | Logical Statement: [XSS Detection] AND NOT([String Match]) 24 | Description: This is useful if you want to whitelist certain pattern from the built-in XSS detection. 25 | 26 | * rule-007.json 27 | Logical Statement: [XSS Detection] AND (NOT([String Match 1]) OR NOT([String Match 2])) 28 | Description: Slightly complicated version of rule-006. This is useful if you want to whitelist certain pattern from the built-in XSS detection. 29 | 30 | * rule-008.json 31 | Logical Statement: [Size Constraint Match] 32 | Description: This will check if certain header exists within the request. 33 | 34 | * rule-009.json 35 | Logical Statement: [Rate Limiting] AND (([String Match 1] OR [String Match 2]) AND NOT([Regex Match])) 36 | Description: This is a rate-limiting rule that will only track IPs that matches the AND condition and its logic inside it. 37 | 38 | * rule-010.json 39 | Logical Statement: NOT([Geo Match 1] OR [Geo Match 2] OR [Geo Match 3] OR [Geo Match 4] OR [Geo Match 5]) 40 | Description: Block requests originating from any country (this example is just to show all supported country code). 41 | 42 | * rule-011.json 43 | Logical Statement: [Rate Based Rule] AND NOT([IP Set Match]) AND NOT([String Match 1]) AND NOT([String Match 2]) 44 | Description: This will cause rate-based rule to trigger only when the conditions are met. Otherwise it will be ignored (not counted). 45 | 46 | * rule-012.json 47 | Logical Statement: NOT([Size Match] AND [String Match]) 48 | Description: Simple example in which NOT statement has multiple objects. 49 | 50 | * rule-013.json 51 | Logical Statement: (AWS Managed Rules - Common Rule Set) 52 | Description: Adds AWS Managed Rules - Common Rule Set. See https://docs.aws.amazon.com/waf/latest/developerguide/aws-managed-rule-groups-list.html for complete list. 53 | 54 | * rule-014.json 55 | Logical Statement: NOT([String Match]) AND ([XSS Detection 1] OR [XSS Detection 2] OR [XSS Detection 3]) 56 | Description: Three XSS detection, each looking at different areas (query string, body, and cookie) with URL whitelist. 57 | 58 | * rule-015.json 59 | Logical Statement: [IP Set Match 1] OR [IP Set Match 2] 60 | Description: WAF allows up to 10,000 IPs for each set. This allows you to merge two IP sets, expanding the pool to 20,000 IP sets. You can list more here as desired. 61 | -------------------------------------------------------------------------------- /JSON/rule-001.json: -------------------------------------------------------------------------------- 1 | { 2 | "Name": "rule-001", 3 | "Priority": 0, 4 | "Action": { 5 | "Block": {} 6 | }, 7 | "VisibilityConfig": { 8 | "SampledRequestsEnabled": true, 9 | "CloudWatchMetricsEnabled": true, 10 | "MetricName": "rule-001" 11 | }, 12 | "Statement": { 13 | "AndStatement": { 14 | "Statements": [ 15 | { 16 | "OrStatement": { 17 | "Statements": [ 18 | { 19 | "ByteMatchStatement": { 20 | "FieldToMatch": { 21 | "SingleHeader": { 22 | "Name": "user-agent" 23 | } 24 | }, 25 | "PositionalConstraint": "EXACTLY", 26 | "SearchString": "apple", 27 | "TextTransformations": [ 28 | { 29 | "Type": "NONE", 30 | "Priority": 0 31 | } 32 | ] 33 | } 34 | }, 35 | { 36 | "ByteMatchStatement": { 37 | "FieldToMatch": { 38 | "SingleHeader": { 39 | "Name": "user-agent" 40 | } 41 | }, 42 | "PositionalConstraint": "EXACTLY", 43 | "SearchString": "orange", 44 | "TextTransformations": [ 45 | { 46 | "Type": "NONE", 47 | "Priority": 0 48 | } 49 | ] 50 | } 51 | } 52 | ] 53 | } 54 | }, 55 | { 56 | "IPSetReferenceStatement": { 57 | "ARN": "arn:aws:wafv2:us-east-1::regional/ipset/" 58 | } 59 | } 60 | ] 61 | } 62 | } 63 | } -------------------------------------------------------------------------------- /JSON/rule-002.json: -------------------------------------------------------------------------------- 1 | { 2 | "Name": "rule-002", 3 | "Priority": 0, 4 | "Action": { 5 | "Block": {} 6 | }, 7 | "VisibilityConfig": { 8 | "SampledRequestsEnabled": true, 9 | "CloudWatchMetricsEnabled": true, 10 | "MetricName": "rule-002" 11 | }, 12 | "Statement": { 13 | "OrStatement": { 14 | "Statements": [ 15 | { 16 | "AndStatement": { 17 | "Statements": [ 18 | { 19 | "RegexPatternSetReferenceStatement": { 20 | "FieldToMatch": { 21 | "AllQueryArguments": {} 22 | }, 23 | "ARN": "arn:aws:wafv2:us-east-1::regional/regexpatternset/", 24 | "TextTransformations": [ 25 | { 26 | "Type": "NONE", 27 | "Priority": 0 28 | } 29 | ] 30 | } 31 | }, 32 | { 33 | "NotStatement": { 34 | "Statement": { 35 | "IPSetReferenceStatement": { 36 | "ARN": "arn:aws:wafv2:us-east-1::regional/ipset/" 37 | } 38 | } 39 | } 40 | } 41 | ] 42 | } 43 | }, 44 | { 45 | "SizeConstraintStatement": { 46 | "FieldToMatch": { 47 | "AllQueryArguments": {} 48 | }, 49 | "ComparisonOperator": "EQ", 50 | "Size": "1337", 51 | "TextTransformations": [ 52 | { 53 | "Type": "NONE", 54 | "Priority": 0 55 | } 56 | ] 57 | } 58 | } 59 | ] 60 | } 61 | } 62 | } -------------------------------------------------------------------------------- /JSON/rule-003.json: -------------------------------------------------------------------------------- 1 | { 2 | "Name": "rule-003", 3 | "Priority": 0, 4 | "Action": { 5 | "Block": {} 6 | }, 7 | "VisibilityConfig": { 8 | "SampledRequestsEnabled": true, 9 | "CloudWatchMetricsEnabled": true, 10 | "MetricName": "rule-003" 11 | }, 12 | "Statement": { 13 | "AndStatement": { 14 | "Statements": [ 15 | { 16 | "NotStatement": { 17 | "Statement": { 18 | "IPSetReferenceStatement": { 19 | "ARN": "arn:aws:wafv2:us-east-1::regional/ipset/" 20 | } 21 | } 22 | } 23 | }, 24 | { 25 | "NotStatement": { 26 | "Statement": { 27 | "RegexPatternSetReferenceStatement": { 28 | "FieldToMatch": { 29 | "AllQueryArguments": {} 30 | }, 31 | "ARN": "arn:aws:wafv2:us-east-1::regional/regexpatternset/", 32 | "TextTransformations": [ 33 | { 34 | "Type": "LOWERCASE", 35 | "Priority": 0 36 | } 37 | ] 38 | } 39 | } 40 | } 41 | }, 42 | { 43 | "NotStatement": { 44 | "Statement": { 45 | "ByteMatchStatement": { 46 | "FieldToMatch": { 47 | "Body": {} 48 | }, 49 | "PositionalConstraint": "EXACTLY", 50 | "SearchString": "abcde", 51 | "TextTransformations": [ 52 | { 53 | "Type": "NONE", 54 | "Priority": 0 55 | } 56 | ] 57 | } 58 | } 59 | } 60 | } 61 | ] 62 | } 63 | } 64 | } -------------------------------------------------------------------------------- /JSON/rule-004.json: -------------------------------------------------------------------------------- 1 | { 2 | "Name": "rule-004", 3 | "Priority": 0, 4 | "Action": { 5 | "Block": {} 6 | }, 7 | "VisibilityConfig": { 8 | "SampledRequestsEnabled": true, 9 | "CloudWatchMetricsEnabled": true, 10 | "MetricName": "rule-004" 11 | }, 12 | "Statement": { 13 | "OrStatement": { 14 | "Statements": [ 15 | { 16 | "ByteMatchStatement": { 17 | "FieldToMatch": { 18 | "SingleHeader": { 19 | "Name": "Host" 20 | } 21 | }, 22 | "PositionalConstraint": "STARTS_WITH", 23 | "SearchString": "block.example.com", 24 | "TextTransformations": [ 25 | { 26 | "Type": "NONE", 27 | "Priority": 0 28 | } 29 | ] 30 | } 31 | }, 32 | { 33 | "ByteMatchStatement": { 34 | "FieldToMatch": { 35 | "SingleQueryArgument": { 36 | "Name": "SessionID" 37 | } 38 | }, 39 | "PositionalConstraint": "EXACTLY", 40 | "SearchString": "12345", 41 | "TextTransformations": [ 42 | { 43 | "Type": "NONE", 44 | "Priority": 0 45 | } 46 | ] 47 | } 48 | }, 49 | { 50 | "ByteMatchStatement": { 51 | "FieldToMatch": { 52 | "AllQueryArguments": {} 53 | }, 54 | "PositionalConstraint": "ENDS_WITH", 55 | "SearchString": "melon", 56 | "TextTransformations": [ 57 | { 58 | "Type": "COMPRESS_WHITE_SPACE", 59 | "Priority": 0 60 | } 61 | ] 62 | } 63 | }, 64 | { 65 | "ByteMatchStatement": { 66 | "FieldToMatch": { 67 | "UriPath": {} 68 | }, 69 | "PositionalConstraint": "CONTAINS_WORD", 70 | "SearchString": "water", 71 | "TextTransformations": [ 72 | { 73 | "Type": "URL_DECODE", 74 | "Priority": 0 75 | } 76 | ] 77 | } 78 | }, 79 | { 80 | "ByteMatchStatement": { 81 | "FieldToMatch": { 82 | "QueryString": {} 83 | }, 84 | "PositionalConstraint": "CONTAINS", 85 | "SearchString": "badbot", 86 | "TextTransformations": [ 87 | { 88 | "Type": "URL_DECODE", 89 | "Priority": 0 90 | } 91 | ] 92 | } 93 | }, 94 | { 95 | "ByteMatchStatement": { 96 | "FieldToMatch": { 97 | "Body": {} 98 | }, 99 | "PositionalConstraint": "CONTAINS", 100 | "SearchString": "oops", 101 | "TextTransformations": [ 102 | { 103 | "Type": "COMPRESS_WHITE_SPACE", 104 | "Priority": 0 105 | } 106 | ] 107 | } 108 | }, 109 | { 110 | "ByteMatchStatement": { 111 | "FieldToMatch": { 112 | "Method": {} 113 | }, 114 | "PositionalConstraint": "CONTAINS", 115 | "SearchString": "GET", 116 | "TextTransformations": [ 117 | { 118 | "Type": "NONE", 119 | "Priority": 0 120 | } 121 | ] 122 | } 123 | } 124 | ] 125 | } 126 | } 127 | } -------------------------------------------------------------------------------- /JSON/rule-005.json: -------------------------------------------------------------------------------- 1 | { 2 | "Name": "rule-005", 3 | "Priority": 0, 4 | "Action": { 5 | "Block": {} 6 | }, 7 | "VisibilityConfig": { 8 | "SampledRequestsEnabled": true, 9 | "CloudWatchMetricsEnabled": true, 10 | "MetricName": "rule-005" 11 | }, 12 | "Statement": { 13 | "AndStatement": { 14 | "Statements": [ 15 | { 16 | "GeoMatchStatement": { 17 | "CountryCodes": [ 18 | "US","CA" 19 | ] 20 | } 21 | }, 22 | { 23 | "NotStatement": { 24 | "Statement": { 25 | "RegexPatternSetReferenceStatement": { 26 | "FieldToMatch": { 27 | "SingleHeader": { 28 | "Name": "host" 29 | } 30 | }, 31 | "ARN": "arn:aws:wafv2:us-east-1::regional/regexpatternset//", 32 | "TextTransformations": [ 33 | { 34 | "Type": "NONE", 35 | "Priority": 0 36 | } 37 | ] 38 | } 39 | } 40 | } 41 | } 42 | ] 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /JSON/rule-006.json: -------------------------------------------------------------------------------- 1 | { 2 | "Name": "rule-006", 3 | "Priority": 0, 4 | "Action": { 5 | "Block": {} 6 | }, 7 | "VisibilityConfig": { 8 | "SampledRequestsEnabled": true, 9 | "CloudWatchMetricsEnabled": true, 10 | "MetricName": "rule-006" 11 | }, 12 | "Statement": { 13 | "AndStatement": { 14 | "Statements": [ 15 | { 16 | "XssMatchStatement": { 17 | "FieldToMatch": { 18 | "Body": {} 19 | }, 20 | "TextTransformations": [ 21 | { 22 | "Type": "URL_DECODE", 23 | "Priority": 0 24 | }, 25 | { 26 | "Type": "HTML_ENTITY_DECODE", 27 | "Priority": 1 28 | } 29 | ] 30 | } 31 | }, 32 | { 33 | "NotStatement": { 34 | "Statement": { 35 | "ByteMatchStatement": { 36 | "FieldToMatch": { 37 | "Body": {} 38 | }, 39 | "PositionalConstraint": "CONTAINS", 40 | "SearchString": "on=", 41 | "TextTransformations": [ 42 | { 43 | "Type": "URL_DECODE", 44 | "Priority": 0 45 | }, 46 | { 47 | "Type": "HTML_ENTITY_DECODE", 48 | "Priority": 1 49 | } 50 | ] 51 | } 52 | } 53 | } 54 | } 55 | ] 56 | } 57 | } 58 | } -------------------------------------------------------------------------------- /JSON/rule-007.json: -------------------------------------------------------------------------------- 1 | { 2 | "Name": "rule-007", 3 | "Priority": 0, 4 | "Action": { 5 | "Block": {} 6 | }, 7 | "VisibilityConfig": { 8 | "SampledRequestsEnabled": true, 9 | "CloudWatchMetricsEnabled": true, 10 | "MetricName": "rule-007" 11 | }, 12 | "Statement": { 13 | "AndStatement": { 14 | "Statements": [ 15 | { 16 | "XssMatchStatement": { 17 | "FieldToMatch": { 18 | "Body": {} 19 | }, 20 | "TextTransformations": [ 21 | { 22 | "Type": "URL_DECODE", 23 | "Priority": 0 24 | }, 25 | { 26 | "Type": "HTML_ENTITY_DECODE", 27 | "Priority": 1 28 | } 29 | ] 30 | } 31 | }, 32 | { 33 | "OrStatement": { 34 | "Statements": [ 35 | { 36 | "NotStatement": { 37 | "Statement": { 38 | "ByteMatchStatement": { 39 | "FieldToMatch": { 40 | "Body": {} 41 | }, 42 | "PositionalConstraint": "CONTAINS", 43 | "SearchString": "style=", 44 | "TextTransformations": [ 45 | { 46 | "Type": "URL_DECODE", 47 | "Priority": 0 48 | }, 49 | { 50 | "Type": "HTML_ENTITY_DECODE", 51 | "Priority": 1 52 | } 53 | ] 54 | } 55 | } 56 | } 57 | }, 58 | { 59 | "NotStatement": { 60 | "Statement": { 61 | "ByteMatchStatement": { 62 | "FieldToMatch": { 63 | "UriPath": {} 64 | }, 65 | "PositionalConstraint": "CONTAINS", 66 | "SearchString": "/uploadimages.php", 67 | "TextTransformations": [ 68 | { 69 | "Type": "LOWERCASE", 70 | "Priority": 0 71 | } 72 | ] 73 | } 74 | } 75 | } 76 | } 77 | ] 78 | } 79 | } 80 | ] 81 | } 82 | } 83 | } -------------------------------------------------------------------------------- /JSON/rule-008.json: -------------------------------------------------------------------------------- 1 | { 2 | "Name": "rule-008", 3 | "Priority": 0, 4 | "Action": { 5 | "Block": {} 6 | }, 7 | "VisibilityConfig": { 8 | "SampledRequestsEnabled": true, 9 | "CloudWatchMetricsEnabled": true, 10 | "MetricName": "rule-008" 11 | }, 12 | "Statement": { 13 | "SizeConstraintStatement": { 14 | "FieldToMatch": { 15 | "SingleHeader": { 16 | "Name": "x-custom-header" 17 | } 18 | }, 19 | "ComparisonOperator": "GE", 20 | "Size": 0, 21 | "TextTransformations": [ 22 | { 23 | "Type": "NONE", 24 | "Priority": 0 25 | } 26 | ] 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /JSON/rule-009.json: -------------------------------------------------------------------------------- 1 | { 2 | "Name": "rbr-with-condition", 3 | "Priority": 0, 4 | "Action": { 5 | "Block": {} 6 | }, 7 | "VisibilityConfig": { 8 | "SampledRequestsEnabled": true, 9 | "CloudWatchMetricsEnabled": true, 10 | "MetricName": "rbr-with-condition" 11 | }, 12 | "Statement": { 13 | "RateBasedStatement": { 14 | "Limit": "1000", 15 | "AggregateKeyType": "IP", 16 | "ScopeDownStatement": { 17 | "AndStatement": { 18 | "Statements": [ 19 | { 20 | "OrStatement": { 21 | "Statements": [ 22 | { 23 | "ByteMatchStatement": { 24 | "FieldToMatch": { 25 | "Method": {} 26 | }, 27 | "PositionalConstraint": "EXACTLY", 28 | "SearchString": "GET", 29 | "TextTransformations": [ 30 | { 31 | "Type": "NONE", 32 | "Priority": 0 33 | } 34 | ] 35 | } 36 | }, 37 | { 38 | "ByteMatchStatement": { 39 | "FieldToMatch": { 40 | "Method": {} 41 | }, 42 | "PositionalConstraint": "EXACTLY", 43 | "SearchString": "POST", 44 | "TextTransformations": [ 45 | { 46 | "Type": "NONE", 47 | "Priority": 0 48 | } 49 | ] 50 | } 51 | } 52 | ] 53 | } 54 | }, 55 | { 56 | "NotStatement": { 57 | "Statement": { 58 | "RegexPatternSetReferenceStatement": { 59 | "FieldToMatch": { 60 | "Body": {} 61 | }, 62 | "ARN": "arn:aws:wafv2:us-east-1::regional/regexpatternset//", 63 | "TextTransformations": [ 64 | { 65 | "Type": "HTML_ENTITY_DECODE", 66 | "Priority": 0 67 | } 68 | ] 69 | } 70 | } 71 | } 72 | } 73 | ] 74 | } 75 | } 76 | } 77 | } 78 | } -------------------------------------------------------------------------------- /JSON/rule-010.json: -------------------------------------------------------------------------------- 1 | { 2 | "Name": "rule-010", 3 | "Priority": 0, 4 | "Action": { 5 | "Block": {} 6 | }, 7 | "VisibilityConfig": { 8 | "SampledRequestsEnabled": true, 9 | "CloudWatchMetricsEnabled": true, 10 | "MetricName": "rule-010" 11 | }, 12 | "Statement": { 13 | "NotStatement": { 14 | "Statement": { 15 | "OrStatement": { 16 | "Statements": [ 17 | { 18 | "GeoMatchStatement": { 19 | "CountryCodes": [ 20 | "AF", "AX", "AL", "DZ", "AS", "AD", "AO", "AI", "AQ", "AG", 21 | "AR", "AM", "AW", "AU", "AT", "AZ", "BS", "BH", "BD", "BB", 22 | "BY", "BE", "BZ", "BJ", "BM", "BT", "BO", "BQ", "BA", "BW", 23 | "BV", "BR", "IO", "BN", "BG", "BF", "BI", "KH", "CM", "CA", 24 | "CV", "KY", "CF", "TD", "CL", "CN", "CX", "CC", "CO", "KM" 25 | ] 26 | } 27 | }, 28 | { 29 | "GeoMatchStatement": { 30 | "CountryCodes": [ 31 | "CG", "CD", "CK", "CR", "CI", "HR", "CU", "CW", "CY", "CZ", 32 | "DK", "DJ", "DM", "DO", "EC", "EG", "SV", "GQ", "ER", "EE", 33 | "ET", "FK", "FO", "FJ", "FI", "FR", "GF", "PF", "TF", "GA", 34 | "GM", "GE", "DE", "GH", "GI", "GR", "GL", "GD", "GP", "GU", 35 | "GT", "GG", "GN", "GW", "GY", "HT", "HM", "VA", "HN", "HK" 36 | ] 37 | } 38 | }, 39 | { 40 | "GeoMatchStatement": { 41 | "CountryCodes": [ 42 | "HU", "IS", "IN", "ID", "IR", "IQ", "IE", "IM", "IL", "IT", 43 | "JM", "JP", "JE", "JO", "KZ", "KE", "KI", "KP", "KR", "KW", 44 | "KG", "LA", "LV", "LB", "LS", "LR", "LY", "LI", "LT", "LU", 45 | "MO", "MK", "MG", "MW", "MY", "MV", "ML", "MT", "MH", "MQ", 46 | "MR", "MU", "YT", "MX", "FM", "MD", "MC", "MN", "ME", "MS" 47 | ] 48 | } 49 | }, 50 | { 51 | "GeoMatchStatement": { 52 | "CountryCodes": [ 53 | "MA", "MZ", "MM", "NA", "NR", "NP", "NL", "NC", "NZ", "NI", 54 | "NE", "NG", "NU", "NF", "MP", "NO", "OM", "PK", "PW", "PS", 55 | "PA", "PG", "PY", "PE", "PH", "PN", "PL", "PT", "QA", "RE", 56 | "RO", "RU", "RW", "BL", "SH", "KN", "LC", "MF", "PM", "VC", 57 | "WS", "SM", "ST", "SA", "SN", "RS", "SC", "SL", "SG", "SX" 58 | ] 59 | } 60 | }, 61 | { 62 | "GeoMatchStatement": { 63 | "CountryCodes": [ 64 | "SK", "SI", "SB", "SO", "ZA", "GS", "SS", "ES", "LK", "SD", 65 | "SR", "SJ", "SZ", "SE", "CH", "SY", "TW", "TJ", "TZ", "TH", 66 | "TL", "TG", "TK", "TO", "TT", "TN", "TR", "TM", "TC", "TV", 67 | "UG", "UA", "AE", "GB", "UM", "UY", "UZ", "VU", "VE", "VN", 68 | "VG", "WF", "EH", "YE", "ZM", "ZW", "US", "VI", "PR" 69 | ] 70 | } 71 | } 72 | ] 73 | } 74 | } 75 | } 76 | } 77 | } -------------------------------------------------------------------------------- /JSON/rule-011.json: -------------------------------------------------------------------------------- 1 | { 2 | "Name": "rule-011", 3 | "Priority": 3, 4 | "Action": { 5 | "Block": {} 6 | }, 7 | "VisibilityConfig": { 8 | "SampledRequestsEnabled": true, 9 | "CloudWatchMetricsEnabled": true, 10 | "MetricName": "rule-011" 11 | }, 12 | "Statement": { 13 | "RateBasedStatement": { 14 | "Limit": "3600", 15 | "AggregateKeyType": "IP", 16 | "ScopeDownStatement": { 17 | "AndStatement": { 18 | "Statements": [ 19 | { 20 | "NotStatement": { 21 | "Statement": { 22 | "IPSetReferenceStatement": { 23 | "ARN": "arn:aws:wafv2:us-east-1::regional/ipset/" 24 | } 25 | } 26 | } 27 | }, 28 | { 29 | "NotStatement": { 30 | "Statement": { 31 | "ByteMatchStatement": { 32 | "FieldToMatch": { 33 | "Method": {} 34 | }, 35 | "PositionalConstraint": "EXACTLY", 36 | "SearchString": "post", 37 | "TextTransformations": [ 38 | { 39 | "Type": "LOWERCASE", 40 | "Priority": 0 41 | } 42 | ] 43 | } 44 | } 45 | } 46 | }, 47 | { 48 | "NotStatement": { 49 | "Statement": { 50 | "ByteMatchStatement": { 51 | "FieldToMatch": { 52 | "SingleHeader": { 53 | "Name": "User-Agent" 54 | } 55 | }, 56 | "PositionalConstraint": "CONTAINS", 57 | "SearchString": "badrobot", 58 | "TextTransformations": [ 59 | { 60 | "Type": "NONE", 61 | "Priority": 0 62 | } 63 | ] 64 | } 65 | } 66 | } 67 | } 68 | ] 69 | } 70 | } 71 | } 72 | } 73 | } -------------------------------------------------------------------------------- /JSON/rule-012.json: -------------------------------------------------------------------------------- 1 | { 2 | "Name": "rule-012", 3 | "Priority": 0, 4 | "Action": { 5 | "Block": {} 6 | }, 7 | "VisibilityConfig": { 8 | "SampledRequestsEnabled": true, 9 | "CloudWatchMetricsEnabled": true, 10 | "MetricName": "rule-012" 11 | }, 12 | "Statement": { 13 | "NotStatement": { 14 | "Statement": { 15 | "AndStatement": { 16 | "Statements": [ 17 | { 18 | "SizeConstraintStatement": { 19 | "FieldToMatch": { 20 | "SingleHeader": { 21 | "Name": "wee" 22 | } 23 | }, 24 | "ComparisonOperator": "EQ", 25 | "Size": "0", 26 | "TextTransformations": [ 27 | { 28 | "Type": "NONE", 29 | "Priority": 0 30 | } 31 | ] 32 | } 33 | }, 34 | { 35 | "ByteMatchStatement": { 36 | "FieldToMatch": { 37 | "SingleHeader": { 38 | "Name": "bah" 39 | } 40 | }, 41 | "PositionalConstraint": "ENDS_WITH", 42 | "SearchString": "wee", 43 | "TextTransformations": [ 44 | { 45 | "Type": "NONE", 46 | "Priority": 0 47 | } 48 | ] 49 | } 50 | } 51 | ] 52 | } 53 | } 54 | } 55 | } 56 | } -------------------------------------------------------------------------------- /JSON/rule-013.json: -------------------------------------------------------------------------------- 1 | { 2 | "Name": "AWS-AWSManagedRulesCommonRuleSet", 3 | "Priority": 1, 4 | "Statement": { 5 | "ManagedRuleGroupStatement": { 6 | "VendorName": "AWS", 7 | "Name": "AWSManagedRulesCommonRuleSet" 8 | } 9 | }, 10 | "OverrideAction": { 11 | "None": {} 12 | }, 13 | "VisibilityConfig": { 14 | "SampledRequestsEnabled": true, 15 | "CloudWatchMetricsEnabled": true, 16 | "MetricName": "AWS-AWSManagedRulesCommonRuleSet" 17 | } 18 | } -------------------------------------------------------------------------------- /JSON/rule-014.json: -------------------------------------------------------------------------------- 1 | { 2 | "Name": "rule-014", 3 | "Priority": 2, 4 | "Action": { 5 | "Block": {} 6 | }, 7 | "VisibilityConfig": { 8 | "SampledRequestsEnabled": true, 9 | "CloudWatchMetricsEnabled": true, 10 | "MetricName": "rule-014" 11 | }, 12 | "Statement": { 13 | "AndStatement": { 14 | "Statements": [ 15 | { 16 | "NotStatement": { 17 | "Statement": { 18 | "ByteMatchStatement": { 19 | "SearchString": "/report/product", 20 | "FieldToMatch": { 21 | "UriPath": {} 22 | }, 23 | "TextTransformations": [ 24 | { 25 | "Priority": 0, 26 | "Type": "NONE" 27 | } 28 | ], 29 | "PositionalConstraint": "STARTS_WITH" 30 | } 31 | } 32 | } 33 | }, 34 | { 35 | "OrStatement": { 36 | "Statements": [ 37 | { 38 | "XssMatchStatement": { 39 | "FieldToMatch": { 40 | "QueryString": {} 41 | }, 42 | "TextTransformations": [ 43 | { 44 | "Priority": 0, 45 | "Type": "URL_DECODE" 46 | } 47 | ] 48 | } 49 | }, 50 | { 51 | "XssMatchStatement": { 52 | "FieldToMatch": { 53 | "Body": {} 54 | }, 55 | "TextTransformations": [ 56 | { 57 | "Priority": 0, 58 | "Type": "HTML_ENTITY_DECODE" 59 | }, 60 | { 61 | "Priority": 1, 62 | "Type": "URL_DECODE" 63 | } 64 | ] 65 | } 66 | }, 67 | { 68 | "XssMatchStatement": { 69 | "FieldToMatch": { 70 | "SingleHeader": { 71 | "Name": "cookie" 72 | } 73 | }, 74 | "TextTransformations": [ 75 | { 76 | "Priority": 0, 77 | "Type": "URL_DECODE" 78 | } 79 | ] 80 | } 81 | } 82 | ] 83 | } 84 | } 85 | ] 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /JSON/rule-015.json: -------------------------------------------------------------------------------- 1 | { 2 | "Name": "rule-015", 3 | "Priority": 0, 4 | "Action": { 5 | "Block": {} 6 | }, 7 | "VisibilityConfig": { 8 | "SampledRequestsEnabled": true, 9 | "CloudWatchMetricsEnabled": true, 10 | "MetricName": "rule-015" 11 | }, 12 | "Statement": { 13 | "OrStatement": { 14 | "Statements": [ 15 | { 16 | "IPSetReferenceStatement": { 17 | "ARN": "arn:aws:wafv2:us-east-1::regional/ipset/" 18 | } 19 | }, 20 | { 21 | "IPSetReferenceStatement": { 22 | "ARN": "arn:aws:wafv2:us-east-1::regional/ipset/" 23 | } 24 | } 25 | ] 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software is furnished to do so. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 10 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 11 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 12 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 13 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 14 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 15 | 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AWS WAF Sample JSON/YAML Model for WAFv2 2 | 3 | This repository contains sample JSON and YAML model that you can use it on your web ACL. We hope that these serve as a guideline and inspiration to write your own rules on AWS WAF. 4 | We also encourage you to share some of the rules that you may have created with broader community as well. For more information on how to write your own rules, please check out some of the link below. 5 | 6 | ### Helpful Links 7 | 8 | [Protecting Your Web Application Using AWS Managed Rules for AWS WAF](https://www.youtube.com/watch?v=ll-uvVgQ3Jg) 9 | 10 | Learn the difference between AWS WAF Classic and WAFv2, and how you can write your own rule using JSON. 11 | 12 | [AWS WAF Developer Guide: Working with managed rule groups](https://docs.aws.amazon.com/waf/latest/developerguide/aws-managed-rule-groups-list.html) 13 | 14 | Take a look at various way to add managed rules to your web ACL. 15 | 16 | [AWS WAF Developer Guide: AWS Managed Rules rule groups list](https://docs.aws.amazon.com/waf/latest/developerguide/waf-using-managed-rule-groups.html) 17 | 18 | See all available managed rule groups that you can add to your web ACL. -------------------------------------------------------------------------------- /YAML/description.txt: -------------------------------------------------------------------------------- 1 | 2 | ** WARNING! ** 3 | In CloudFormation, you can only write 3 level of nested rule statements max. This is because CloudFormation does not allow recursive operation. 4 | You may need to reduce or optimize nested statements that you may have (e.g. NOT(A AND B) instead of NOT(A) AND NOT(B)), or use custom resources functionality. 5 | 6 | * snippet-001.yaml 7 | Description: This is a snippet that you can reference to for associating web ACL to ALB. 8 | 9 | * webacl-create-001.yaml 10 | Description: This will create a web ACL with AWS Managed Ruleset (Common Rule Set) enabled and exluding a rule inside it. 11 | 12 | * webacl-create-002.yaml 13 | Description: This will create a web ACL with block rule having IP set and string match for excluding specific host domain. 14 | 15 | * webacl-create-003.yaml 16 | Description: This will create a web ACL with block rule having XSS detection on query string and string match for excluding specific pattern. 17 | -------------------------------------------------------------------------------- /YAML/snippet-001.yaml: -------------------------------------------------------------------------------- 1 | ## Associate WAFv2 Web ACL with a load balancer 2 | ## Alb = AWS::ElasticLoadBalancingV2::LoadBalancer 3 | ## webACL = AWS::WAFv2::WebACL 4 | 5 | wafALBAssociation: 6 | Type: AWS::WAFv2::WebACLAssociation 7 | Properties: 8 | ResourceArn: 9 | !Sub 10 | - 'arn:aws:elasticloadbalancing:${AWS::Region}:${AWS::AccountId}:loadbalancer/${TargetALB}' 11 | - TargetALB: !GetAtt Alb.LoadBalancerFullName 12 | WebACLArn: !GetAtt wafACL.Arn 13 | -------------------------------------------------------------------------------- /YAML/webacl-create-001.yaml: -------------------------------------------------------------------------------- 1 | Description: This will create a web ACL with AWS Managed Ruleset (Common Rule Set) enabled and exluding a rule inside it. 2 | 3 | Resources: 4 | WebACLWithAMR: 5 | Type: AWS::WAFv2::WebACL 6 | Properties: 7 | Name: WebACLWithAMR 8 | Scope: REGIONAL 9 | Description: This is a demo web ACL with AWS Managed Rules 10 | DefaultAction: 11 | Block: {} 12 | VisibilityConfig: 13 | SampledRequestsEnabled: true 14 | CloudWatchMetricsEnabled: true 15 | MetricName: MetricForWebACLWithAMR 16 | Tags: 17 | - Key: sampleapple 18 | Value: sampleorange 19 | Rules: 20 | - Name: AWS-AWSManagedRulesCommonRuleSet 21 | Priority: 0 22 | OverrideAction: 23 | None: {} 24 | VisibilityConfig: 25 | SampledRequestsEnabled: true 26 | CloudWatchMetricsEnabled: true 27 | MetricName: MetricForAMRCRS 28 | Statement: 29 | ManagedRuleGroupStatement: 30 | VendorName: AWS 31 | Name: AWSManagedRulesCommonRuleSet 32 | ExcludedRules: 33 | - Name: NoUserAgent_HEADER 34 | -------------------------------------------------------------------------------- /YAML/webacl-create-002.yaml: -------------------------------------------------------------------------------- 1 | Description: This will create a web ACL with block rule having IP set and string match for excluding specific host domain. 2 | 3 | Resources: 4 | TestWebACLForCFN: 5 | Type: AWS::WAFv2::WebACL 6 | Properties: 7 | Name: TestWebACLForCFN 8 | Scope: REGIONAL 9 | Description: WebACL CloudFormation Test 10 | DefaultAction: 11 | Block: {} 12 | VisibilityConfig: 13 | SampledRequestsEnabled: true 14 | CloudWatchMetricsEnabled: true 15 | MetricName: TestWebACLForCFNMetric 16 | 17 | Rules: 18 | - Name: IPSetWithException 19 | Priority: 1 20 | Action: 21 | Block: {} 22 | VisibilityConfig: 23 | SampledRequestsEnabled: true 24 | CloudWatchMetricsEnabled: true 25 | MetricName: IPSetWithExceptionMetric 26 | Statement: 27 | AndStatement: 28 | Statements: 29 | - IPSetReferenceStatement: 30 | ARN: arn:aws:wafv2:us-east-1::regional/ipset// 31 | - NotStatement: 32 | Statement: 33 | ByteMatchStatement: 34 | FieldToMatch: 35 | SingleHeader: 36 | Name: host 37 | PositionalConstraint: EXACTLY 38 | SearchString: dev.appleorange.com 39 | TextTransformations: 40 | - Type: NONE 41 | Priority: 0 -------------------------------------------------------------------------------- /YAML/webacl-create-003.yaml: -------------------------------------------------------------------------------- 1 | Description: This will create a web ACL with block rule having XSS detection on query string and string match for excluding specific pattern. 2 | 3 | Resources: 4 | TestWebACLForCFN: 5 | Type: AWS::WAFv2::WebACL 6 | Properties: 7 | Name: TestWebACLForCFN 8 | Scope: REGIONAL 9 | Description: WebACL CloudFormation Test For XSS Exclude 10 | DefaultAction: 11 | Block: {} 12 | VisibilityConfig: 13 | SampledRequestsEnabled: true 14 | CloudWatchMetricsEnabled: true 15 | MetricName: TestWebACLForCFNMetric 16 | 17 | Rules: 18 | - Name: XSSWithException 19 | Priority: 1 20 | Action: 21 | Block: {} 22 | VisibilityConfig: 23 | SampledRequestsEnabled: true 24 | CloudWatchMetricsEnabled: true 25 | MetricName: XSSWithExceptionMetric 26 | Statement: 27 | AndStatement: 28 | Statements: 29 | - XssMatchStatement: 30 | FieldToMatch: 31 | QueryString: {} 32 | TextTransformations: 33 | - Priority: 1 34 | Type: URL_DECODE 35 | - Priority: 2 36 | Type: HTML_ENTITY_DECODE 37 | - NotStatement: 38 | Statement: 39 | ByteMatchStatement: 40 | FieldToMatch: 41 | QueryString: {} 42 | PositionalConstraint: CONTAINS 43 | SearchString: on= 44 | TextTransformations: 45 | - Type: NONE 46 | Priority: 0 --------------------------------------------------------------------------------