chaitin-waf
#
DescriptionThe chaitin-waf
Plugin integrates with the Chaitin WAF (SafeLine) service to provide advanced detection and prevention of web-based threats, enhancing application security and protecting sensitive user data.
#
Response HeadersThe Plugin can add the following response headers, depending on the configuration of append_waf_resp_header
and append_waf_debug_header
:
Header | Description |
---|---|
X-APISIX-CHAITIN-WAF | Indicates whether APISIX forwarded the request to the WAF server. • yes : Request was forwarded to the WAF server.• no : Request was not forwarded to the WAF server.• unhealthy : Request matches the configured rules, but no WAF service is available.• err : An error occurred during Plugin execution. The X-APISIX-CHAITIN-WAF-ERROR header is also included with details.• waf-err : Error while interacting with the WAF server. The X-APISIX-CHAITIN-WAF-ERROR header is also included with details.• timeout : Request to the WAF server timed out. |
X-APISIX-CHAITIN-WAF-TIME | Round-trip time (RTT) in milliseconds for the request to the Chaitin WAF server, including both network latency and WAF server processing. |
X-APISIX-CHAITIN-WAF-STATUS | Status code returned to APISIX by the WAF server. |
X-APISIX-CHAITIN-WAF-ACTION | Action returned to APISIX by the WAF server. • pass : Request was allowed by the WAF service.• reject : Request was blocked by the WAF service. |
X-APISIX-CHAITIN-WAF-ERROR | Debug header. Contains WAF error message. |
X-APISIX-CHAITIN-WAF-SERVER | Debug header. Indicates which WAF server was selected. |
#
AttributesName | Type | Required | Default | Valid values | Description |
---|---|---|---|---|---|
mode | string | false | block | off , monitor , block | Mode to determine how the Plugin behaves for matched requests. In off mode, WAF checks are skipped. In monitor mode, requests with potential threats are logged but not blocked. In block mode, requests with threats are blocked as determined by the WAF service. |
match | array[object] | false | An array of matching rules. The Plugin uses these rules to decide whether to perform a WAF check on a request. If the list is empty, all requests are processed. | ||
match.vars | array[array] | false | An array of one or more matching conditions in the form of lua-resty-expr to conditionally execute the plugin. | ||
append_waf_resp_header | boolean | false | true | If true, add response headers X-APISIX-CHAITIN-WAF , X-APISIX-CHAITIN-WAF-TIME , X-APISIX-CHAITIN-WAF-ACTION , and X-APISIX-CHAITIN-WAF-STATUS . | |
append_waf_debug_header | boolean | false | false | If true, add debugging headers X-APISIX-CHAITIN-WAF-ERROR and X-APISIX-CHAITIN-WAF-SERVER to the response. Effective only when append_waf_resp_header is true . | |
config | object | false | Chaitin WAF service configurations. These settings override the corresponding metadata defaults when specified. | ||
config.connect_timeout | integer | false | 1000 | The connection timeout to the WAF service, in milliseconds. | |
config.send_timeout | integer | false | 1000 | The sending timeout for transmitting data to the WAF service, in milliseconds. | |
config.read_timeout | integer | false | 1000 | The reading timeout for receiving data from the WAF service, in milliseconds. | |
config.req_body_size | integer | false | 1024 | The maximum allowed request body size, in KB. | |
config.keepalive_size | integer | false | 256 | The maximum number of idle connections to the WAF detection service that can be maintained concurrently. | |
config.keepalive_timeout | integer | false | 60000 | The idle connection timeout for the WAF service, in milliseconds. | |
config.real_client_ip | boolean | false | true | If true, the client IP is obtained from the X-Forwarded-For header. If false, the Plugin uses the client IP from the connection. |
#
Plugin MetadataName | Type | Required | Default | Valid values | Description |
---|---|---|---|---|---|
nodes | array[object] | True | An array of addresses for the Chaitin WAF service. | ||
nodes.host | string | True | Address of Chaitin WAF service. Supports IPv4, IPv6, Unix Socket, etc. | ||
nodes.port | integer | False | 80 | Port of Chaitin WAF service. | |
mode | string | False | block | Mode to determine how the Plugin behaves for matched requests. In off mode, WAF checks are skipped. In monitor mode, requests with potential threats are logged but not blocked. In block mode, requests with threats are blocked as determined by the WAF service. | |
config | object | False | Chaitin WAF service configurations. | ||
config.connect_timeout | integer | False | 1000 | The connection timeout to the WAF service, in milliseconds. | |
config.send_timeout | integer | False | 1000 | The sending timeout for transmitting data to the WAF service, in milliseconds. | |
config.read_timeout | integer | False | 1000 | The reading timeout for receiving data from the WAF service, in milliseconds. | |
config.req_body_size | integer | False | 1024 | The maximum allowed request body size, in KB. | |
config.keepalive_size | integer | False | 256 | The maximum number of idle connections to the WAF detection service that can be maintained concurrently. | |
config.keepalive_timeout | integer | False | 60000 | The idle connection timeout for the WAF service, in milliseconds. | |
config.real_client_ip | boolean | False | true | If true, the client IP is obtained from the X-Forwarded-For header. If false, the Plugin uses the client IP from the connection. |
#
ExamplesThe examples below demonstrate how you can configure chaitin-waf Plugin for different scenarios.
Before proceeding, make sure you have installed Chaitin WAF (SafeLine).
note
Only X-Forwarded-*
headers sent from addresses in the apisix.trusted_addresses
configuration (supports IP and CIDR) will be trusted and passed to plugins or upstream. If apisix.trusted_addresses
is not configured or the IP is not within the configured address range, all X-Forwarded-*
headers will be overridden with trusted values.
note
You can fetch the admin_key
from config.yaml
and save to an environment variable with the following command:
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
#
Block Malicious Requests on a RouteThe following example demonstrates how to integrate with Chaitin WAF to protect traffic on a route, rejecting malicious requests immediately.
Configure the Chaitin WAF connection details using Plugin Metadata (update the address accordingly):
curl "http://127.0.0.1:9180/apisix/admin/plugin_metadata/chaitin-waf" -X PUT \
-H 'X-API-KEY: ${admin_key}' \
-d '{
"nodes": [
{
"host": "172.22.222.5",
"port": 8000
}
]
}'
Create a Route and enable chaitin-waf
on the Route to block requests identified to be malicious:
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "chaitin-waf-route",
"uri": "/anything",
"plugins": {
"chaitin-waf": {
"mode": "block",
"append_waf_resp_header": true,
"append_waf_debug_header": true
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
Send a standard request to the Route:
curl -i "http://127.0.0.1:9080/anything"
You should receive an HTTP/1.1 200 OK
response.
Send a request with SQL injection to the Route:
curl -i "http://127.0.0.1:9080/anything" -d 'a=1 and 1=1'
You should see an HTTP/1.1 403 Forbidden
response similar to the following:
...
X-APISIX-CHAITIN-WAF-STATUS: 403
X-APISIX-CHAITIN-WAF-ACTION: reject
X-APISIX-CHAITIN-WAF-SERVER: 172.22.222.5
X-APISIX-CHAITIN-WAF: yes
X-APISIX-CHAITIN-WAF-TIME: 3
...
{"code": 403, "success":false, "message": "blocked by Chaitin SafeLine Web Application Firewall", "event_id": "276be6457d8447a4bf1f792501dfba6c"}
#
Monitor Requests for Malicious IntentThis example shows how to integrate with Chaitin WAF to monitor all routes with chaitin-waf
without rejection, and to reject potentially malicious requests on a specific route.
Configure the Chaitin WAF connection details using Plugin Metadata (update the address accordingly) and configure the mode:
curl "http://127.0.0.1:9180/apisix/admin/plugin_metadata/chaitin-waf" -X PUT \
-H 'X-API-KEY: ${admin_key}' \
-d '{
"nodes": [
{
"host": "172.22.222.5",
"port": 8000
}
],
"mode": "monitor"
}'
Create a Route and enable chaitin-waf
without any configuration on the Route:
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "chaitin-waf-route",
"uri": "/anything",
"plugins": {
"chaitin-waf": {}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
Send a standard request to the Route:
curl -i "http://127.0.0.1:9080/anything"
You should receive an HTTP/1.1 200 OK
response.
Send a request with SQL injection to the Route:
curl -i "http://127.0.0.1:9080/anything" -d 'a=1 and 1=1'
You should also receive an HTTP/1.1 200 OK
response as the request is not blocked in the monitor
mode, but observe the following in the log entry:
2025/09/09 11:44:08 [warn] 115#115: *31683 [lua] chaitin-waf.lua:385: do_access(): chaitin-waf monitor mode: request would have been rejected, event_id: 49bed20603e242f9be5ba6f1744bba4b, client: 172.20.0.1, server: _, request: "POST /anything HTTP/1.1", host: "127.0.0.1:9080"
If you explicitly configure the mode
on a route, it will take precedence over the configuration in the Plugin Metadata. For instance, if you create a Route like this:
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "chaitin-waf-route",
"uri": "/anything",
"plugins": {
"chaitin-waf": {
"mode": "block"
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
Send a standard request to the Route:
curl -i "http://127.0.0.1:9080/anything"
You should receive an HTTP/1.1 200 OK
response.
Send a request with SQL injection to the Route:
curl -i "http://127.0.0.1:9080/anything" -d 'a=1 and 1=1'
You should see an HTTP/1.1 403 Forbidden
response similar to the following:
...
X-APISIX-CHAITIN-WAF-STATUS: 403
X-APISIX-CHAITIN-WAF-ACTION: reject
X-APISIX-CHAITIN-WAF: yes
X-APISIX-CHAITIN-WAF-TIME: 3
...
{"code": 403, "success":false, "message": "blocked by Chaitin SafeLine Web Application Firewall", "event_id": "c3eb25eaa7ae4c0d82eb8ceebf3600d0"}