What WAFs Do and Where They Stop
A Web Application Firewall sits in front of your application, inspecting HTTP traffic before it reaches your server. It maintains a rule set β patterns that look like SQL injection, XSS payloads, directory traversal attempts β and blocks requests that match.
WAFs are genuinely useful. They block automated scanner noise, provide a compensating control for known vulnerabilities while patches are being developed, and can significantly raise the cost of an attack by requiring a motivated attacker to craft bypass payloads rather than using off-the-shelf tools.
The fundamental limitation is positional. A WAF sees the HTTP request β the raw bytes of the request before they're processed by your application. It doesn't know what your application is going to do with those bytes. It can't see inside your application's logic.
WAF bypass is a discipline: There are entire research tracks, conference talks, and toolkits dedicated to WAF evasion. Double encoding, Unicode normalization tricks, HTTP parameter pollution, case variation, comment injection β a skilled attacker with a specific target will test bypass techniques systematically until one works. The WAF blocks the easy exploitation; it doesn't prevent determined exploitation.
What RASP Is and How It Works
Runtime Application Self-Protection is a security technology that's embedded directly into the application itself. It instruments the runtime β hooking into system calls, library calls, or the language runtime β and monitors the application's behaviour from inside the process.
When RASP detects that the application is about to perform a dangerous operation β executing a SQL query that contains what looks like an injection payload, making a file system call to a path outside the expected directory, executing a shell command β it can block the operation, log it, or both.
RASP is language and runtime specific. Java RASP uses Java agents and bytecode instrumentation. Python RASP instruments the CPython runtime. Node.js RASP uses module patching. Each approach hooks into the relevant dangerous call sites.
The Key Architectural Difference: Perimeter vs In-Process
The WAF sees: GET /search?q=1'+OR+'1'='1 HTTP/1.1 β a suspicious query string. It may or may not recognise this as a SQLi pattern depending on the encoding used.
RASP sees: "the application is about to call db.execute("SELECT * FROM products WHERE id = '1' OR '1'='1'")" β the actual SQL that will be executed, after all application-layer processing, decoding, and transformation. No encoding tricks fool RASP because it sees the final, decoded value at the exact point of execution.
# RASP intercepts at the DB execution layer # Conceptual representation of what a Python RASP hook does: import sqlite3 _original_execute = sqlite3.Cursor.execute def rasp_execute(self, sql, params=None): # RASP checks the actual SQL being executed if detect_sql_injection(sql): rasp_alert(f"SQL injection blocked: {sql[:100]}") raise SecurityException("Request blocked by RASP") return _original_execute(self, sql, params) # Monkey-patch the execute method sqlite3.Cursor.execute = rasp_execute # Now any attempt to execute injected SQL is blocked # regardless of what encoding was used in the HTTP request
What RASP Can Catch That WAFs Miss
- Encoded injection attacks: WAF sees
%27%20OR%20%271%27%3D%271. RASP sees the decoded value at execution time. No bypass. - Second-order injection: Input is stored cleanly, then later retrieved and used in a query. The WAF only saw the initial storage request β which looked clean. RASP intercepts at execution, regardless of how the data got there.
- Application-layer deserialization attacks: An attack that exploits an insecure deserialization vulnerability looks like a normal HTTP request to the WAF. RASP can detect the dangerous class instantiation at the runtime level.
- Zero-day vulnerabilities: RASP doesn't rely on signatures β it monitors behaviour. An attack exploiting a new, unknown vulnerability still has to eventually do something at the system call level (read a file, execute a command, make a network connection). If that behaviour is anomalous, RASP can block it without needing a signature.
--- Attack payload that bypasses WAF but not RASP --- // WAF sees (URL encoded, WAF doesn't match): GET /search?q=%27%20UNION%20SELECT%20null%2Cpassword%20FROM%20users-- // RASP sees at execution (decoded, anomalous SQL detected): SELECT * FROM products WHERE name = '' UNION SELECT null,password FROM users-- // WAF: passes (encoding trick defeated signature match) // RASP: blocks (sees the actual SQL, detects UNION injection)
Zero-Day Protection: How Behavioural Detection Works
The most compelling RASP use case is zero-day protection. When Log4Shell dropped in December 2021, organisations with RASP in place had a meaningful advantage β even before the vulnerability was fully understood, RASP's behavioural monitoring detected the JNDI lookup attempts and blocked the actual exploitation, because a Java app making outbound LDAP connections as a result of processing a log message is anomalous behaviour.
Behavioural detection works because vulnerabilities, while diverse in mechanism, tend to converge on a narrow set of dangerous final actions: file reads outside expected paths, shell command execution, unexpected outbound network connections, privilege escalation calls. RASP watches these chokepoints.
Performance Overhead Reality Check
The traditional objection to RASP is performance overhead. This is legitimate but often overstated. Modern RASP implementations add 3-8% overhead in typical applications β acceptable for most use cases, particularly when the alternative is operating without the protection RASP provides.
The heavy-overhead scenarios are applications making very high volumes of database calls or file system operations, where the interception cost adds up. RASP vendors typically provide profiling tools to identify hot paths and can configure selective instrumentation to reduce overhead in performance-critical code.
eBPF-based RASP: A newer generation of RASP implementations uses eBPF (extended Berkeley Packet Filter) for syscall-level monitoring with significantly lower overhead than traditional language agent approaches. eBPF runs in the kernel and can observe system calls with minimal performance impact. This is particularly relevant for containerised deployments.
RASP in Containers and Serverless
Containerised and serverless deployments have complicated traditional RASP deployment models β you can't run a persistent agent in a function that spins up and down in milliseconds. The approaches that work:
- Sidecar pattern: A separate RASP sidecar container handles the monitoring, connected via eBPF or network interception. Works in Kubernetes with a DaemonSet-deployed agent.
- Lambda layer (AWS): RASP deployed as a Lambda Layer that wraps the function execution. AWS's own AppShield and third-party options are available for Node.js and Python runtimes.
- Service mesh integration: Envoy proxy sidecar can be extended with WASM plugins that provide some RASP-like capabilities at the network layer.
RASP + WAF as Defence-in-Depth
RASP and WAF aren't competing β they're complementary layers with different strengths.
- WAF strengths: Rate limiting, geographic blocking, bot protection, blocking known-bad IPs, compliance reporting (WAF is often a PCI-DSS requirement)
- RASP strengths: Post-decode detection, second-order attack detection, zero-day protection, application-context awareness
The layered model: WAF blocks volume attacks, scanners, and known-bad patterns at the perimeter. RASP catches sophisticated attacks that bypass the WAF and get through to the application. The two layers together provide coverage that neither provides alone.
When Is RASP Worth the Investment?
RASP makes the most sense in these scenarios:
- Applications with known vulnerabilities that can't be patched immediately: RASP provides a compensating control while remediation is scheduled
- High-value targets: Financial services, healthcare, critical infrastructure β where the cost of a breach justifies additional protection layers
- Regulatory environments: Some compliance frameworks (PCI-DSS 4.0, for example) now recognise RASP as a compensating control
- Legacy applications: Applications where code-level fixes are impractical because the team that wrote them is gone or the codebase is too large to audit
For organisations still maturing their application security programme, the priority order is usually: fix the code (SAST/code review), test it (DAST), then add runtime protection as a defence-in-depth layer. RASP is not a substitute for fixing the underlying vulnerabilities.
Find Vulnerabilities Before They Need Runtime Protection
AquilaX DAST and SAST provide complementary pre-deployment coverage β catch vulnerabilities in code and running applications before they reach production.
Start Free Scan