chaitin-waf
The 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 Headers
The 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. |
Report Responses to WAF
Response reporting was introduced in API7 Enterprise 3.9.20 and 3.10.7, and in APISIX 3.19.0. It lets the WAF service observe the response status, headers, and a bounded body sample after the gateway serves the response. It does not block or modify that response.
Enable reporting in the plugin's config object on a route, or in the metadata config object to set the default for all routes:
{
"log_resp": true,
"resp_body_size": 4
}The example keeps the default body limit of 4 KiB; reporting is disabled by default. Set the body limit to 0 to report only status and headers. Response content types in the built-in ignored list or extra_ignored_content_types are not reported at all.
The report is sent asynchronously, but collecting the sample still uses gateway memory during the response. Account for concurrent responses when increasing the limit, avoid sending sensitive response data unnecessarily, and monitor response-reporting errors in the gateway log.
Examples
The examples below demonstrate how you can configure chaitin-waf plugin for different scenarios.
Before proceeding, make sure you have installed Chaitin WAF (SafeLine).
Block Malicious Requests on a Route
The 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_API_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_API_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
}
}
}'❶ Set mode to block to block requests identified to be malicious.
❷ Set append_waf_resp_header to true to include WAF-related standard response headers.
❸ Set append_waf_debug_header to true to include WAF-related debugging response headers.
plugin_metadata:
chaitin-waf:
nodes:
- host: "172.22.222.5"
port: 8000
services:
- name: chaitin-waf-service
routes:
- name: chaitin-waf-route
uris:
- /anything
plugins:
chaitin-waf:
mode: block
append_waf_resp_header: true
append_waf_debug_header: true
upstream:
type: roundrobin
nodes:
- host: httpbin.org
port: 80
weight: 1Synchronize the configuration to the gateway:
adc sync -f adc.yaml❶ nodes: List of Chaitin WAF service addresses. Update the host and port to match your Chaitin WAF (SafeLine) deployment.
❷ Set mode to block to block requests identified to be malicious.
❸ Set append_waf_resp_header to true to include WAF-related standard response headers.
❹ Set append_waf_debug_header to true to include WAF-related debugging response headers.
Update your GatewayProxy manifest to configure the plugin metadata. If Chaitin WAF is installed on a host machine outside the cluster, use the host's IP address. In most deployments, expose Chaitin WAF as a reachable Service, IP address, or DNS name inside the cluster, or use the node/LoadBalancer address instead.
apiVersion: apisix.apache.org/v1alpha1
kind: GatewayProxy
metadata:
namespace: aic
name: apisix-config
spec:
provider:
type: ControlPlane
controlPlane:
# ...
# your control plane connection configuration
pluginMetadata:
chaitin-waf:
nodes:
- host: "172.22.222.5"
port: 8000❶ nodes: List of Chaitin WAF service addresses. Update the host and port to match your Chaitin WAF (SafeLine) deployment.
Create a route with chaitin-waf to block malicious requests:
apiVersion: v1
kind: Service
metadata:
namespace: aic
name: httpbin-external-domain
spec:
type: ExternalName
externalName: httpbin.org
---
apiVersion: apisix.apache.org/v1alpha1
kind: PluginConfig
metadata:
namespace: aic
name: chaitin-waf-plugin-config
spec:
plugins:
- name: chaitin-waf
config:
mode: block
append_waf_resp_header: true
append_waf_debug_header: true
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
namespace: aic
name: chaitin-waf-route
spec:
parentRefs:
- name: apisix
rules:
- matches:
- path:
type: Exact
value: /anything
filters:
- type: ExtensionRef
extensionRef:
group: apisix.apache.org
kind: PluginConfig
name: chaitin-waf-plugin-config
backendRefs:
- name: httpbin-external-domain
port: 80Apply the configuration to your cluster:
kubectl apply -f gatewayproxy.yaml -f chaitin-waf-ic.yamlCreate a route with chaitin-waf to block malicious requests:
apiVersion: apisix.apache.org/v2
kind: ApisixUpstream
metadata:
namespace: aic
name: httpbin-external-domain
spec:
ingressClassName: apisix
externalNodes:
- type: Domain
name: httpbin.org
---
apiVersion: apisix.apache.org/v2
kind: ApisixRoute
metadata:
namespace: aic
name: chaitin-waf-route
spec:
ingressClassName: apisix
http:
- name: chaitin-waf-route
match:
paths:
- /anything
upstreams:
- name: httpbin-external-domain
plugins:
- name: chaitin-waf
enable: true
config:
mode: block
append_waf_resp_header: true
append_waf_debug_header: trueApply the configuration to your cluster:
kubectl apply -f gatewayproxy.yaml -f chaitin-waf-ic.yaml❷ Set mode to block to block requests identified to be malicious.
❸ Set append_waf_resp_header to true to include WAF-related standard response headers.
❹ Set append_waf_debug_header to true to include WAF-related debugging response headers.
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 Intent
This 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_API_KEY}" \
-d '{
"nodes": [
{
"host": "172.22.222.5",
"port": 8000
}
],
"mode": "monitor"
}'❶ Set mode to monitor in the plugin metadata. This applies to all chaitin-waf plugin instances if mode is not specified on a route.
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_API_KEY}" \
-d '{
"id": "chaitin-waf-route",
"uri": "/anything",
"plugins": {
"chaitin-waf": {}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'plugin_metadata:
chaitin-waf:
nodes:
- host: "172.22.222.5"
port: 8000
mode: monitor
services:
- name: chaitin-waf-service
routes:
- name: chaitin-waf-route
uris:
- /anything
plugins:
chaitin-waf: {}
upstream:
type: roundrobin
nodes:
- host: httpbin.org
port: 80
weight: 1Synchronize the configuration to the gateway:
adc sync -f adc.yaml❶ nodes: List of Chaitin WAF service addresses. Update the host and port to match your Chaitin WAF (SafeLine) deployment.
❷ Set mode to monitor in the plugin metadata. This applies to all chaitin-waf plugin instances if mode is not specified on a route.
Update your GatewayProxy manifest to configure the plugin metadata. If Chaitin WAF is installed on a host machine outside the cluster, use the host's IP address. In most deployments, expose Chaitin WAF as a reachable Service, IP address, or DNS name inside the cluster, or use the node/LoadBalancer address instead.
apiVersion: apisix.apache.org/v1alpha1
kind: GatewayProxy
metadata:
namespace: aic
name: apisix-config
spec:
provider:
type: ControlPlane
controlPlane:
# ...
# your control plane connection configuration
pluginMetadata:
chaitin-waf:
nodes:
- host: "172.22.222.5"
port: 8000
mode: monitor❶ Set mode to monitor in the plugin metadata. This applies to all chaitin-waf plugin instances if mode is not specified on a route.
Create a route with chaitin-waf enabled without any plugin-level configuration, so it inherits the monitor mode from the plugin metadata:
apiVersion: v1
kind: Service
metadata:
namespace: aic
name: httpbin-external-domain
spec:
type: ExternalName
externalName: httpbin.org
---
apiVersion: apisix.apache.org/v1alpha1
kind: PluginConfig
metadata:
namespace: aic
name: chaitin-waf-plugin-config
spec:
plugins:
- name: chaitin-waf
config: {}
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
namespace: aic
name: chaitin-waf-route
spec:
parentRefs:
- name: apisix
rules:
- matches:
- path:
type: Exact
value: /anything
filters:
- type: ExtensionRef
extensionRef:
group: apisix.apache.org
kind: PluginConfig
name: chaitin-waf-plugin-config
backendRefs:
- name: httpbin-external-domain
port: 80Apply the configuration to your cluster:
kubectl apply -f gatewayproxy.yaml -f chaitin-waf-ic.yamlTo override the monitor mode and block malicious requests on the route, update the PluginConfig to set mode: block:
# other configs
# ---
apiVersion: apisix.apache.org/v1alpha1
kind: PluginConfig
metadata:
namespace: aic
name: chaitin-waf-plugin-config
spec:
plugins:
- name: chaitin-waf
config:
mode: blockApply the updated configuration to your cluster:
kubectl apply -f chaitin-waf-ic.yamlCreate a route with chaitin-waf enabled without any plugin-level configuration, so it inherits the monitor mode from the plugin metadata:
apiVersion: apisix.apache.org/v2
kind: ApisixUpstream
metadata:
namespace: aic
name: httpbin-external-domain
spec:
ingressClassName: apisix
externalNodes:
- type: Domain
name: httpbin.org
---
apiVersion: apisix.apache.org/v2
kind: ApisixRoute
metadata:
namespace: aic
name: chaitin-waf-route
spec:
ingressClassName: apisix
http:
- name: chaitin-waf-route
match:
paths:
- /anything
upstreams:
- name: httpbin-external-domain
plugins:
- name: chaitin-waf
enable: true
config: {}Apply the configuration to your cluster:
kubectl apply -f gatewayproxy.yaml -f chaitin-waf-ic.yamlTo override the monitor mode and block malicious requests on the route, update the ApisixRoute to set mode: block:
# other configs
# ---
apiVersion: apisix.apache.org/v2
kind: ApisixRoute
metadata:
namespace: aic
name: chaitin-waf-route
spec:
ingressClassName: apisix
http:
- name: chaitin-waf-route
match:
paths:
- /anything
upstreams:
- name: httpbin-external-domain
plugins:
- name: chaitin-waf
enable: true
config:
mode: blockApply the updated configuration to your cluster:
kubectl apply -f chaitin-waf-ic.yamlSend 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_API_KEY}" \
-d '{
"id": "chaitin-waf-route",
"uri": "/anything",
"plugins": {
"chaitin-waf": {
"mode": "block"
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'plugin_metadata:
chaitin-waf:
nodes:
- host: "172.22.222.5"
port: 8000
mode: monitor
services:
- name: chaitin-waf-service
routes:
- name: chaitin-waf-route
uris:
- /anything
plugins:
chaitin-waf:
mode: block
upstream:
type: roundrobin
nodes:
- host: httpbin.org
port: 80
weight: 1Synchronize the configuration to the gateway:
adc sync -f adc.yamlUpdate the PluginConfig to set mode: block:
# other configs
# ---
apiVersion: apisix.apache.org/v1alpha1
kind: PluginConfig
metadata:
namespace: aic
name: chaitin-waf-plugin-config
spec:
plugins:
- name: chaitin-waf
config:
mode: blockApply the updated configuration to your cluster:
kubectl apply -f chaitin-waf-ic.yamlUpdate the ApisixRoute to set mode: block:
# other configs
# ---
apiVersion: apisix.apache.org/v2
kind: ApisixRoute
metadata:
namespace: aic
name: chaitin-waf-route
spec:
ingressClassName: apisix
http:
- name: chaitin-waf-route
match:
paths:
- /anything
upstreams:
- name: httpbin-external-domain
plugins:
- name: chaitin-waf
enable: true
config:
mode: blockApply the updated configuration to your cluster:
kubectl apply -f chaitin-waf-ic.yamlSend 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"}