Skip to content

Commit abc65ea

Browse files
Support WAF (#1482)
* [enhancement] add controller fw * [enhancement] imp some methods * [enhancement] WIP fw * [enhancement] all flow can work with test case * introduce owasp coreruleset, refactor rules and rulegroup * support waf control without coraza * [enhancement] refactor * [enhancement] add api * add waf process reqesut part * fix waf process body bug * add tests for sql injection and fix waf bugs * add tests for xss attack * add tests for remote code exec (RCE) attack * remove unused codes, add comments * add test for protocol attacks * support ip block for wafcontroller * [enhancement] finish api & metrics collection * add test for bot detection * update ip blocker logic make it more reasonable * refactor rule related codes * add basic logic of geoip blocker * [enhancement] add filter * merge to main * [testing] add basic test case for filter & controller * [testing] test case for custom settings * test upload file attacks with multipart * [testing] test case for ip blocker * test local file inclusion attack * test generic attacks for waf * [testing] test case for geo ip * add WAF doc of introdution, wafcontroller, waffilter and custom spec * [testing] refactor * simplify waf setup conf * add more docs * add doc for wafcontroller and waf filter * [testing] remove unused conf * fix race condition in testing * fix go version * fix go mod * try to fix windows path error * skip some test on windows since coraza crs not support windows for now --------- Co-authored-by: chen <chen.su1994@outlook.com>
1 parent ce7c368 commit abc65ea

File tree

20 files changed

+4060
-13
lines changed

20 files changed

+4060
-13
lines changed
Lines changed: 260 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,260 @@
1+
# Web Application Firewall <!-- omit from toc -->
2+
3+
4+
- [Introduction](#introduction)
5+
- [Configuring Web Application Firewall](#configuring-web-application-firewall)
6+
- [Custom](#custom)
7+
- [OWASP Core Rule Set](#owasp-core-rule-set)
8+
- [IP Blocker](#ip-blocker)
9+
- [Whitelist Mode](#whitelist-mode)
10+
- [Blacklist Mode](#blacklist-mode)
11+
- [Combined Mode (Whitelist \& Blacklist)](#combined-mode-whitelist--blacklist)
12+
- [GEO IP Blocker](#geo-ip-blocker)
13+
- [Whitelist Mode (allowedCountries)](#whitelist-mode-allowedcountries)
14+
- [Blacklist Mode (deniedCountries)](#blacklist-mode-deniedcountries)
15+
- [Rate Limiter](#rate-limiter)
16+
- [Observability](#observability)
17+
18+
19+
## Introduction
20+
21+
The Web Application Firewall (WAF) protects your apps by inspecting HTTP(S) traffic and blocking malicious requests at the application layer. It supports standard rule sets like OWASP CRS and flexible custom policies.
22+
23+
Beyond basic request filtering, the WAF includes IP/Geo access control, rate limiting, and rich observability for tuning and incident response. This ensures strong protection with low false positives and clear operational insight.
24+
25+
## Configuring Web Application Firewall
26+
27+
Here is a simple example shows how to configure Easegress to protect your backend using a WAF with a minimal subset of the OWASP Core Rule Set (CRS) focused on SQL Injection (SQLi) detection.
28+
29+
```yaml
30+
name: waf-controller
31+
kind: WAFController
32+
ruleGroups:
33+
- name: sqlinjection
34+
rules:
35+
customRules: |
36+
// https://github.com/corazawaf/coraza-coreruleset/blob/main/rules/%40crs-setup.conf.example
37+
// check coraza core rule set recommend setup file
38+
owaspRules:
39+
- REQUEST-901-INITIALIZATION.conf
40+
- REQUEST-942-APPLICATION-ATTACK-SQLI.conf
41+
- REQUEST-949-BLOCKING-EVALUATION.conf
42+
43+
------
44+
45+
name: waf-server
46+
kind: HTTPServer
47+
port: 10080
48+
rules:
49+
- paths:
50+
- pathPrefix: /
51+
backend: waf-pipeline
52+
53+
-----
54+
55+
name: waf-pipeline
56+
kind: Pipeline
57+
filters:
58+
- name: waf-filter
59+
kind: WAF
60+
ruleGroup: sqlinjection
61+
- name: proxy
62+
kind: Proxy
63+
pools:
64+
- servers:
65+
- url: http://127.0.0.1:9095
66+
- url: http://127.0.0.1:9096
67+
loadBalance:
68+
policy: roundRobin
69+
```
70+
71+
It will do following things:
72+
73+
1. Loads a minimal, SQLi-focused subset of the OWASP CRS:
74+
- 901: Initialization and variable setup
75+
- 942: SQL Injection detection
76+
- 949: Final blocking evaluation
77+
2. Routes traffic to port 10080 through the waf-pipeline, where the WAF filter evaluates requests against the sqlinjection rule group before proxying to your backend pool.
78+
79+
### Custom
80+
81+
This example shows how to load the full OWASP Core Rule Set (CRS) and add your own custom Coraza/ModSecurity rules in Easegress. The example below blocks all POST requests at both `phase 1` and `phase 2` for demonstration purposes.
82+
83+
```yaml
84+
name: waf-controller
85+
kind: WAFController
86+
ruleGroups:
87+
- name: sqlinjection
88+
rules:
89+
loadOwaspCrs: true
90+
customRules: |
91+
SecRule REQUEST_METHOD "POST" "id:1000001,phase:1,block,log,msg:'Block all POST requests (phase 1)',severity:'CRITICAL'"
92+
SecRule REQUEST_METHOD "POST" "id:1000002,phase:2,block,log,msg:'Block all POST requests (phase 2)',severity:'CRITICAL'"
93+
```
94+
95+
What this does:
96+
97+
- `loadOwaspCrs`: true loads the full OWASP CRS bundle. You can includes them as you needed. For full rule set, please check: [here](https://github.com/corazawaf/coraza-coreruleset/tree/main/rules/%40owasp_crs).
98+
- `customRules` adds two rules that explicitly block all POST requests. They run in different phases to illustrate the request processing lifecycle. For more details about Coraza/Modsecurity rules please check: [here](https://coraza.io/docs/seclang/)
99+
100+
Feel free to add your own rules as needed.
101+
102+
### OWASP Core Rule Set
103+
104+
This example shows how to use the corazawaf/coraza-coreruleset package to protect your applications. This package provides a straightforward way to embed the official OWASP Core Rule Set (CRS) directly into a Go application using the Coraza Web Application Firewall (WAF).
105+
106+
To effectively use the CRS, a proper setup is essential. This involves including foundational configuration files that define the behavior of both the Coraza engine and the rule set itself.
107+
108+
Coraza Configuration [@coraza.conf-recommended](https://github.com/corazawaf/coraza-coreruleset/blob/main/rules/%40coraza.conf-recommended): This file provides the recommended base settings for the Coraza WAF engine.
109+
110+
CRS Setup [@crs-setup.conf.example](https://github.com/corazawaf/coraza-coreruleset/blob/main/rules/%40crs-setup.conf.example): This file is crucial for customizing the Core Rule Set. Here, you can configure paranoia levels, anomaly score thresholds, and other CRS-specific behaviors. You should copy this file and tailor it to your application's needs.
111+
112+
```yaml
113+
name: waf-controller
114+
kind: WAFController
115+
ruleGroups:
116+
- name: sqlinjection
117+
rules:
118+
customRules: |
119+
// https://github.com/corazawaf/coraza-coreruleset/blob/main/rules/%40crs-setup.conf.example
120+
// The crs-setup.conf file is required for CRS to function.
121+
// This is a minimal example; a full setup file offers more customization.
122+
SecRequestBodyAccess On
123+
SecDefaultAction "phase:1,log,auditlog,pass"
124+
SecDefaultAction "phase:2,log,auditlog,pass"
125+
SecAction \
126+
"id:900990,\
127+
phase:1,\
128+
pass,\
129+
t:none,\
130+
nolog,\
131+
tag:'OWASP_CRS',\
132+
ver:'OWASP_CRS/4.16.0',\
133+
setvar:tx.crs_setup_version=4160"
134+
owaspRules:
135+
- REQUEST-901-INITIALIZATION.conf
136+
- REQUEST-913-SCANNER-DETECTION.conf
137+
- REQUEST-921-PROTOCOL-ATTACK.conf
138+
- REQUEST-922-MULTIPART-ATTACK.conf
139+
- REQUEST-949-BLOCKING-EVALUATION.conf
140+
```
141+
142+
For all rules, please check [here](https://github.com/corazawaf/coraza-coreruleset/tree/main/rules/%40owasp_crs).
143+
144+
### IP Blocker
145+
146+
The `ipBlocker` rule filters requests based on the source IP address, specified in `CIDR` format.
147+
148+
#### Whitelist Mode
149+
150+
Logic: Allows requests only from IPs on the list. All others are blocked.
151+
152+
```yaml
153+
kind: WAFController
154+
name: waf-controller
155+
ruleGroups:
156+
- name: ipblocker
157+
rules:
158+
ipBlocker:
159+
whitelist:
160+
- 136.252.0.2/32
161+
```
162+
163+
#### Blacklist Mode
164+
165+
Logic: Blocks requests from IPs on the list. All others are allowed.
166+
167+
```yaml
168+
kind: WAFController
169+
name: waf-controller
170+
ruleGroups:
171+
- name: ipblocker
172+
rules:
173+
ipBlocker:
174+
blacklist:
175+
- 158.160.2.1/32
176+
```
177+
178+
#### Combined Mode (Whitelist & Blacklist)
179+
180+
Logic: Blocks request if IP is in blacklist OR not in whitelist.
181+
182+
```yaml
183+
kind: WAFController
184+
name: waf-controller
185+
ruleGroups:
186+
- name: ipblocker
187+
rules:
188+
ipBlocker:
189+
whitelist:
190+
- 136.252.0.2/32
191+
blacklist:
192+
- 158.160.2.1/32
193+
```
194+
195+
### GEO IP Blocker
196+
197+
The `geoIPBlocker` rule allows or denies requests based on the visitor's country of origin. It requires a GeoIP database to function.
198+
199+
- `dbPath`: The file path to your GeoIP database (.mmdb file).
200+
- `dbUpdateCron`: (Optional) A cron expression to schedule automatic updates for the database.
201+
- `Country Codes`: Use standard two-letter ISO codes (e.g., US, CN).
202+
203+
#### Whitelist Mode (allowedCountries)
204+
205+
Logic: Only allows requests from the specified countries. All other countries will be blocked.
206+
207+
```yaml
208+
kind: WAFController
209+
name: waf-controller
210+
ruleGroups:
211+
- name: geoipblocker
212+
rules:
213+
geoIPBlocker:
214+
dbPath: <your-dir>/Country.mmdb
215+
allowedCountries:
216+
- XX
217+
```
218+
219+
#### Blacklist Mode (deniedCountries)
220+
221+
Logic: Blocks requests from the specified countries. All other countries will be allowed.
222+
223+
```yaml
224+
kind: WAFController
225+
name: waf-controller
226+
ruleGroups:
227+
- name: geoipblocker
228+
rules:
229+
geoIPBlocker:
230+
dbPath: <your-dir>/Country.mmdb
231+
dbUpdateCron: "0 0 1 * *"
232+
deniedCountries:
233+
- XX
234+
```
235+
236+
### Rate Limiter
237+
238+
The RateLimiter restricts how many requests a client can make within a specific time window (e.g., requests per second). This is a crucial defense against brute-force attacks and helps prevent system overload from excessive traffic.
239+
240+
For detailed configuration, please refer to the official documentation for the built-in Easegress RateLimiter filter [here](./../07.Reference/7.02.Filters.md#ratelimiter).
241+
242+
## Observability
243+
244+
To monitor requests blocked by the WAF, you can use the `waf_total_refused_requests` counter metric exposed to Prometheus. This metric increments every time a request is denied by a WAF rule.
245+
246+
It includes several labels to help you pinpoint the cause of the block:
247+
248+
Common Labels:
249+
250+
- `kind`, `clusterName`, `clusterRole`, `instanceName`: Standard labels to identify the Easegress instance.
251+
252+
Metric-Specific Labels:
253+
254+
- `ruleGroup`: The name of the rule group that blocked the request.
255+
- `ruleID`: The ID of the specific rule that was triggered.
256+
- `action`: The WAF action, canbe one of `drop`, `deny`, `redirect`.
257+
258+
Using these labels, you can create detailed dashboards and alerts, for instance, to track which rules are most active or to identify repeated block events from a specific source.
259+
260+
For a complete list of all available metrics, please see the [Metrics](../07.Reference/7.08.Metrics.md) reference documentation.

docs/07.Reference/7.01.Controllers.md

Lines changed: 72 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
- [NacosServiceRegistry](#nacosserviceregistry)
2222
- [AutoCertManager](#autocertmanager)
2323
- [AIGatewayController](#aigatewaycontroller)
24+
- [WAFController](#wafcontroller)
2425
- [Common Types](#common-types)
2526
- [tracing.Spec](#tracingspec)
2627
- [spanlimits.Spec](#spanlimitsspec)
@@ -47,14 +48,18 @@
4748
- [resilience.Policy](#resiliencepolicy)
4849
- [Retry Policy](#retry-policy)
4950
- [CircuitBreaker Policy](#circuitbreaker-policy)
50-
- [aigatewaycontroller.ProviderSpec](#aigatewaycontrollerproviderspec)
51+
- [AIGatewayController.ProviderSpec](#aigatewaycontrollerproviderspec)
5152
- [Supported Providers](#supported-providers)
52-
- [aigatewaycontroller.MiddlewareSpec](#aigatewaycontrollermiddlewarespec)
53-
- [aigatewaycontroller.SemanticCacheSpec](#aigatewaycontrollersemanticcachespec)
54-
- [aigatewaycontroller.EmbeddingSpec](#aigatewaycontrollerembeddingspec)
55-
- [aigatewaycontroller.VectorDBSpec](#aigatewaycontrollervectordbspec)
56-
- [aigatewaycontroller.RedisSpec](#aigatewaycontrollerredisspec)
57-
- [aigatewaycontroller.PostgresSpec](#aigatewaycontrollerpostgresspec)
53+
- [AIGatewayController.MiddlewareSpec](#aigatewaycontrollermiddlewarespec)
54+
- [AIGatewayController.SemanticCacheSpec](#aigatewaycontrollersemanticcachespec)
55+
- [AIGatewayController.EmbeddingSpec](#aigatewaycontrollerembeddingspec)
56+
- [AIGatewayController.VectorDBSpec](#aigatewaycontrollervectordbspec)
57+
- [AIGatewayController.RedisSpec](#aigatewaycontrollerredisspec)
58+
- [AIGatewayController.PostgresSpec](#aigatewaycontrollerpostgresspec)
59+
- [WAFController.RuleGroupSpec](#wafcontrollerrulegroupspec)
60+
- [WAFController.RuleSpec](#wafcontrollerrulespec)
61+
- [WAFController.IPBlockerSpec](#wafcontrolleripblockerspec)
62+
- [WAFController.GeoIPBlockerSpec](#wafcontrollergeoipblockerspec)
5863

5964
As the [architecture diagram](../imgs/architecture.png) shows, the controller is the core entity to control kinds of working. There are two kinds of controllers overall:
6065

@@ -627,6 +632,37 @@ version: easegress.megaease.com/v2
627632
| providers | [][ProviderSpec](#aigatewaycontrollerproviderspec) | List of AI providers configuration | No |
628633
| middlewares | [][MiddlewareSpec](#aigatewaycontrollermiddlewarespec) | List of middleware configuration for request processing | No |
629634

635+
636+
### WAFController
637+
638+
```yaml
639+
name: waf-controller
640+
kind: WAFController
641+
ruleGroups:
642+
- name: sqlinjection
643+
rules:
644+
customRules: |
645+
// https://github.com/corazawaf/coraza-coreruleset/blob/main/rules/%40crs-setup.conf.example
646+
// check coraza core rule set recommend setup file
647+
owaspRules:
648+
- REQUEST-901-INITIALIZATION.conf
649+
- REQUEST-942-APPLICATION-ATTACK-SQLI.conf
650+
- REQUEST-949-BLOCKING-EVALUATION.conf
651+
- name: geoipblocker
652+
rules:
653+
geoIPBlocker:
654+
dbPath: <your-dir>/Country.mmdb
655+
dbUpdateCron: "0 0 1 * *"
656+
deniedCountries:
657+
- XX
658+
```
659+
660+
661+
| Name | Type | Description | Required |
662+
| ----------- | ----------------------------------------- | ----------------------------------------------------- | -------- |
663+
|ruleGroups | [][RuleGroupSpec](#wafcontrollerrulegroupspec) | A list of configurations for one or more WAF rule groups. | Yes |
664+
665+
630666
## Common Types
631667

632668
### tracing.Spec
@@ -1002,3 +1038,32 @@ The providerType can be one of the following:
10021038
| Name | Type | Description | Required |
10031039
| ------------- | ------ | ------------------------------ | -------- |
10041040
| connectionURL | string | PostgreSQL connection URL | Yes |
1041+
1042+
### WAFController.RuleGroupSpec
1043+
| Name | Type | Description | Required |
1044+
| ----------- | ----------------------------------------- | ----------------------------------------------------- | -------- |
1045+
| name | string | A unique name for the rule group. | Yes |
1046+
| loadOwaspCrs | bool | Indicates whether to load the OWASP Core Rule Set. For more details, please check Coraza CRS. | No |
1047+
| rules | [RuleSpec](#wafcontrollerrulespec) | Defines the specific rules included in this rule group. | Yes |
1048+
1049+
### WAFController.RuleSpec
1050+
| Name | Type | Description | Required |
1051+
| ----------- | ----------------------------------------- | ----------------------------------------------------- | -------- |
1052+
| owaspRules | []string | Defines the OWASP rules to be applied. See the examples at Coraza CRS for more details. | No |
1053+
| customRules | string | Defines custom WAF rules. | No |
1054+
| ipBlocker | [IPBlockerSpec](#wafcontrolleripblockerspec) | Defines access control rules based on IP addresses (whitelist/blacklist). | No |
1055+
| geoIPBlocker | [GeoIPBlockerSpec](#wafcontrollergeoipblockerspec) | Defines access control rules based on geolocation (GeoIP). | No |
1056+
1057+
### WAFController.IPBlockerSpec
1058+
| Name | Type | Description | Required |
1059+
| ----------- | ----------------------------------------- | ----------------------------------------------------- | -------- |
1060+
| whitelist | []string | A list of IP addresses that are allowed access. | No |
1061+
| blacklist | []string | A list of IP addresses that are denied access. | No |
1062+
1063+
### WAFController.GeoIPBlockerSpec
1064+
| Name | Type | Description | Required |
1065+
| ----------- | ----------------------------------------- | ----------------------------------------------------- | -------- |
1066+
| dbPath | string | The file path to the GeoIP database. | Yes |
1067+
| dbUpdateCron | string | A cron expression for automatically updating the GeoIP database on a schedule. | No |
1068+
| allowedCountries | []string | A list of country codes (e.g., "US", "CN") that are allowed access. | No |
1069+
| deniedCountries | []string | A list of country codes that are denied access. | No|

0 commit comments

Comments
 (0)