RASP at CDN Edge: Runtime Application Self-Protection

· Michael Chen · 10 min read

Web Application Firewalls have been the default perimeter defense for over a decade. They inspect incoming HTTP traffic, match it against signature databases, and block requests that look malicious. The problem is that attackers have learned to evade pattern-matching defenses through encoding tricks, request fragmentation, and novel payload structures that WAF signatures have never seen. Runtime Application Self-Protection takes a fundamentally different approach: instead of guessing whether a request looks dangerous from the outside, RASP monitors what the application actually does when processing that request. For background on traditional edge security defenses, see CDN WAF: Edge Security Rules.

How RASP Differs from WAF

A WAF sits in front of the application as a reverse proxy, analyzing HTTP requests and responses against a rule database. It operates on the transport layer — headers, URLs, query strings, and request bodies — without understanding what the application does with that data. When the application receives a query parameter and uses it in a database query, the WAF has already made its allow/block decision based solely on the parameter's appearance in the HTTP request.

RASP operates inside the application runtime. It instruments the actual points where dangerous operations occur: database query execution, file system access, command execution, outbound network connections, and deserialization. When the application constructs a SQL query, RASP sees the final query string and can determine whether user input was concatenated into it unsafely. This distinction matters because the same HTTP parameter might be safe in one code path and dangerous in another — context that a WAF cannot see.

WAF vs RASP Detection Points WAF vs RASP — Where Detection Happens Client HTTP Request WAF Layer Pattern matching Signature database ❌ No app context Application Runtime Request processing Database queries File I/O, syscalls Response 200 / 403 RASP Instrumentation Points SQL Query Builder Detect injected clauses File System Access Block path traversal Command Execution Prevent OS injection Deserialization Validate object types WAF Blind Spots • Encoded payloads bypass signatures • No visibility into app logic • Zero-day attacks have no signatures RASP Advantages • Monitors actual application behavior • Context-aware detection • Zero-day protection by design
Figure 1: WAF inspects requests at the perimeter; RASP instruments operations inside the application runtime

RASP at the CDN Edge: Architecture Patterns

Deploying RASP at CDN edge locations creates a distributed security mesh that protects application logic running closest to users. Edge compute platforms — Cloudflare Workers, Fastly Compute, AWS Lambda@Edge — execute application code at hundreds of points of presence worldwide. Each execution context needs its own RASP instrumentation because the application logic runs independently at each edge location.

Performance Comparison: Edge vs Origin Processing
Metric Edge Processing Origin Processing Improvement
Latency (p50)8–15 ms120–300 ms15–20x faster
Cache Hit Ratio85–95%N/AReduces origin load
TLS Handshake1–5 ms (nearby PoP)50–150 ms10–30x faster
Bandwidth Cost$0.01–0.04/GB$0.05–0.12/GB3–5x cheaper
Availability99.99% (multi-PoP)99.9% (single DC)10x fewer outages

The edge RASP architecture wraps the platform APIs that edge functions use to interact with external systems. When an edge function calls a database, makes a fetch request to an origin, or accesses a KV store, the RASP layer intercepts and validates the operation. This interception happens at the API boundary, not at the network level, giving RASP full visibility into the operation parameters and context.

// Edge RASP middleware pattern for Cloudflare Workers
class EdgeRASP {
  constructor(config) {
    this.config = config;
    this.originalFetch = globalThis.fetch;
    this.instrumentFetch();
  }

  instrumentFetch() {
    const rasp = this;
    globalThis.fetch = async function(input, init) {
      const url = typeof input === 'string' ? new URL(input) : input.url;

      // Check for SSRF attempts
      if (rasp.isInternalNetwork(url)) {
        rasp.log('BLOCKED', 'ssrf_attempt', { url: url.toString() });
        return new Response('Forbidden', { status: 403 });
      }

      // Check for data exfiltration patterns
      if (rasp.containsSensitiveData(init?.body)) {
        rasp.log('ALERT', 'data_exfiltration', { destination: url.host });
        return new Response('Forbidden', { status: 403 });
      }

      return rasp.originalFetch.call(globalThis, input, init);
    };
  }

  isInternalNetwork(url) {
    const hostname = url.hostname;
    return hostname.startsWith('10.') ||
           hostname.startsWith('172.') ||
           hostname.startsWith('192.168.') ||
           hostname === 'localhost' ||
           hostname === '169.254.169.254'; // AWS metadata
  }

  containsSensitiveData(body) {
    if (!body || typeof body !== 'string') return false;
    // Detect common sensitive data patterns
    const patterns = [
      /\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b/g, // emails
      /\b\d{3}-\d{2}-\d{4}\b/g, // SSN
      /\b(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14})\b/g, // credit cards
    ];
    return patterns.some(p => p.test(body));
  }
}

SQL Injection Detection with Context

Traditional WAFs detect SQL injection by scanning request parameters for SQL keywords like UNION SELECT, OR 1=1, and DROP TABLE. Attackers bypass these checks with encoding, case mixing, comment insertion, and Unicode substitution. RASP takes a different approach: it monitors the actual SQL query that the application constructs and compares the query structure with and without the user input.

When user input changes the structure of a SQL query — adding new clauses, joining additional tables, or modifying the WHERE condition logic — RASP detects this as injection regardless of how the input was encoded or obfuscated in the HTTP request. The detection works on the semantics of the query, not the syntax of the input.

// RASP SQL injection detection at the query execution point
function raspQueryGuard(query, params, userInputs) {
  // Parse the query into an AST
  const ast = sqlParser.parse(query);

  // Build a "clean" AST with placeholders instead of user input
  const cleanQuery = query;
  for (const input of userInputs) {
    cleanQuery.replaceAll(input, '?placeholder?');
  }
  const cleanAst = sqlParser.parse(cleanQuery);

  // Compare structural elements
  if (ast.tables.length !== cleanAst.tables.length) {
    throw new RASPViolation('sql_injection',
      'User input added additional table references');
  }

  if (ast.whereConditions.length !== cleanAst.whereConditions.length) {
    throw new RASPViolation('sql_injection',
      'User input modified WHERE clause structure');
  }

  if (ast.hasUnion && !cleanAst.hasUnion) {
    throw new RASPViolation('sql_injection',
      'User input introduced UNION query');
  }

  // Query structure is unchanged — safe to execute
  return database.execute(query, params);
}

Deserialization Attack Prevention

Deserialization vulnerabilities allow attackers to execute arbitrary code by sending crafted serialized objects to applications that deserialize user-controlled data. These attacks are particularly dangerous because they often achieve remote code execution — the highest severity classification. WAFs struggle with deserialization attacks because the malicious payload is embedded inside serialized data formats (Java serialization, PHP serialization, Python pickle, JSON with type hints) that look like normal application data.

RASP prevents deserialization attacks by monitoring the deserialization process itself. It maintains an allowlist of classes that the application legitimately deserializes and blocks any attempt to instantiate classes outside this list. When a deserialization operation tries to create an instance of a known dangerous class (like java.lang.Runtime or os.system), RASP blocks it before the object is constructed.

SSRF Protection at the Edge

Server-Side Request Forgery is especially dangerous at CDN edge locations because edge functions often have network access to internal services, metadata endpoints, and origin servers. An SSRF vulnerability in an edge function can expose cloud provider credentials (via instance metadata services), access internal APIs, or scan the internal network. For more on origin server protection strategies, see CDN Origin Server Configuration.

RASP protects against SSRF by intercepting all outbound network requests from the application and validating the destination against a policy. The policy defines which hosts, ports, and protocols the application is expected to communicate with. Any request to an unexpected destination — particularly internal IP ranges, cloud metadata services, and localhost — is blocked and logged.

# RASP SSRF protection policy
rasp:
  outbound_policy:
    allowed_hosts:
      - api.example.com
      - cdn-origin.example.com
      - analytics.example.com
    blocked_networks:
      - 10.0.0.0/8        # Private Class A
      - 172.16.0.0/12     # Private Class B
      - 192.168.0.0/16    # Private Class C
      - 169.254.0.0/16    # Link-local (AWS metadata)
      - 127.0.0.0/8       # Loopback
      - fd00::/8           # IPv6 private
    blocked_ports:
      - 22    # SSH
      - 3306  # MySQL
      - 5432  # PostgreSQL
      - 6379  # Redis
    allowed_protocols:
      - https
    alert_on:
      - dns_rebinding      # hostname resolves to internal IP
      - redirect_to_internal # HTTP redirect targets internal network

Performance Considerations

RASP instrumentation adds overhead to every request. At CDN edge locations where latency targets are measured in single-digit milliseconds, this overhead requires careful management. The key is selective instrumentation: not every operation needs every check on every request.

Profile your application to identify which RASP checks provide the most security value for each endpoint. A static asset endpoint needs minimal RASP instrumentation. An API endpoint that processes user input into database queries needs SQL injection detection. An endpoint that deserializes request bodies needs deserialization guards. Configure RASP policies per route rather than applying uniform instrumentation across all traffic.

Cache RASP decisions where possible. If RASP has validated that a particular query template is safe, subsequent requests using the same template with different parameter values can skip the full structural analysis. This template caching can reduce RASP overhead by 60-80% for applications with predictable query patterns.

Deployment Strategy

Deploy RASP in observation mode first. In this mode, RASP monitors and logs all detections without blocking any requests. Run observation mode for at least two weeks in production to build a baseline of normal application behavior and identify false positives. Review every detection to determine whether it represents a real attack or a legitimate application behavior that RASP incorrectly flagged.

After tuning, switch individual detection categories to blocking mode one at a time. Start with the highest-confidence detections — SSRF to metadata endpoints, deserialization of known dangerous classes — and gradually expand to broader categories like SQL injection structural analysis. This staged approach minimizes the risk of blocking legitimate traffic while building confidence in RASP accuracy.

Integrate RASP telemetry with your existing CDN monitoring and observability pipeline. RASP generates high-value security signals that complement your WAF logs, CDN access logs, and application metrics. Correlate RASP detections with WAF decisions to identify attacks that bypass your perimeter defenses — these are the attacks where RASP provides the most value. For incident handling when RASP detects active exploitation, see CDN Incident Response Playbooks.

External References

References & Standards: RFC 7234 · OWASP CDN Security