Skip to main content

chaitin-waf

The chaitin-waf plugin sends request information to the SafeLine detection service before proxying traffic upstream. SafeLine identifies web threats such as SQL injection, cross-site scripting, command injection, and path traversal.

The plugin can block detected threats or monitor them without interrupting traffic. A route-level mode overrides the mode configured in plugin metadata.

Response Headers​

When response headers are enabled, the plugin can add the following fields:

HeaderDescription
X-APISIX-CHAITIN-WAFProcessing result.
yes: SafeLine checked the request.
no: matching rules skipped the check.
off: the plugin mode disabled checks.
unhealthy: no detector was available.
err: plugin processing failed.
waf-err: detector communication failed.
timeout: the detector request timed out.
X-APISIX-CHAITIN-WAF-TIMESafeLine request round-trip time, in milliseconds.
X-APISIX-CHAITIN-WAF-STATUSStatus reported by the SafeLine detector.
X-APISIX-CHAITIN-WAF-ACTIONSafeLine decision: pass or reject.
X-APISIX-CHAITIN-WAF-ERRORDebug header containing an error message.
X-APISIX-CHAITIN-WAF-SERVERDebug header identifying the selected detector.

append_waf_resp_header controls the standard headers. append_waf_debug_header additionally exposes the error and server headers and should normally be limited to troubleshooting.

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 following examples configure SafeLine and use the plugin to block or monitor malicious requests.

Set Up SafeLine​

The examples use a SafeLine detector that the gateway reaches through the T1K protocol on TCP port 8000. Install SafeLine by following the official deployment guide.

In the SafeLine installation directory, update the existing detector configuration with these settings:

resources/detector/detector.yml (relevant settings)
bind_addr: 0.0.0.0
listen_port: 8000

Restart the detector after saving the configuration:

docker restart safeline-detector

For a gateway running in Docker on the same host, connect it to SafeLine's installation network and use the detector container name:

export GATEWAY_CONTAINER=replace-with-gateway-container-name

docker network connect safeline-ce "$GATEWAY_CONTAINER"
export WAF_HOST=safeline-detector

For other deployments, expose TCP port 8000 only to the gateway network and set WAF_HOST to a reachable DNS name or IP address:

export WAF_HOST=replace-with-safeline-detector-host

Configure the Detector Address​

The detector node list is plugin metadata shared by all chaitin-waf instances.

curl "http://127.0.0.1:9180/apisix/admin/plugin_metadata/chaitin-waf" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d @- <<EOF
{
"nodes": [
{
"host": "$WAF_HOST",
"port": 8000
}
]
}
EOF

When neither plugin metadata nor a route sets mode, current gateway releases use monitor.

With the detector address configured, the following examples block threats on one route, monitor threats without blocking, and override a metadata-level mode on an individual route.

Block Malicious Requests​

The following example demonstrates how to configure a route that blocks threats detected by SafeLine.

Configure the route:

curl "http://127.0.0.1:9180/apisix/admin/routes/chaitin-waf-block" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"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
}
}
}'

mode: block rejects detected threats. The response headers expose the SafeLine decision and, for this diagnostic example, the selected detector.

Send a normal request:

curl -i "http://127.0.0.1:9080/anything/get"

The response should be 200 OK and include X-APISIX-CHAITIN-WAF-ACTION: pass.

Send a request containing SQL injection:

curl -i "http://127.0.0.1:9080/anything/get?id=1%20union%20select%201,2,3"

The response should contain fields similar to the following:

HTTP/1.1 403 Forbidden
X-APISIX-CHAITIN-WAF-ACTION: reject
X-APISIX-CHAITIN-WAF-STATUS: 403
X-APISIX-CHAITIN-WAF: yes

{"code": 403, "success":false, "message": "blocked by Chaitin SafeLine Web Application Firewall", "event_id": "..."}

Monitor Threats without Blocking​

The following example demonstrates how to monitor detected threats without interrupting traffic.

Set the shared metadata mode to monitor while retaining the detector nodes configured earlier:

curl "http://127.0.0.1:9180/apisix/admin/plugin_metadata/chaitin-waf" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d @- <<EOF
{
"nodes": [
{
"host": "$WAF_HOST",
"port": 8000
}
],
"mode": "monitor"
}
EOF

Create a route that inherits the metadata mode:

curl "http://127.0.0.1:9180/apisix/admin/routes/chaitin-waf-monitor" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"uri": "/monitor/*",
"plugins": {
"chaitin-waf": {
"append_waf_resp_header": true,
"append_waf_debug_header": true
},
"proxy-rewrite": {
"regex_uri": ["^/monitor/(.*)", "/anything/$1"]
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'

Send the SQL injection request through the monitoring route:

curl -i "http://127.0.0.1:9080/monitor/get?id=1%20union%20select%201,2,3"

The request should reach the upstream and return 200 OK. The response headers should still include X-APISIX-CHAITIN-WAF-ACTION: reject and X-APISIX-CHAITIN-WAF-STATUS: 403, while the gateway error log records chaitin-waf monitor mode: request would have been rejected.

Override Monitor Mode on a Route​

The following example demonstrates how route-level configuration overrides the shared monitoring mode for one route.

Set mode: block on the monitoring route to override the metadata-level mode:

curl "http://127.0.0.1:9180/apisix/admin/routes/chaitin-waf-monitor" -X PATCH \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"plugins": {
"chaitin-waf": {
"mode": "block",
"append_waf_resp_header": true,
"append_waf_debug_header": true
}
}
}'

Repeat the SQL injection request. The route should now return 403 Forbidden, confirming that route configuration takes precedence over plugin metadata.