Skip to main content

Someone wanted to learn this too, so Grasp built them a personal learning path.

You can keep exploring this one or create your own

Session Tracking for Stateful WAF & Multi-Request Attack Correlation

Hello! Welcome back to our course on architecting security products.

In our last lesson, we designed an anomaly scoring engine that evaluates the risk of a single HTTP request by combining multiple weak signals. This was a huge step up from simple signature matching, allowing our WAF to make more nuanced decisions. However, that engine has a significant blind spot: it's stateless. It judges each request in isolation, unable to see the broader context of a user's session.

Many sophisticated attacks don't happen in a single request. They unfold over time as a sequence of actions.

Example of a Multi-Stage Attack
This diagram illustrates a typical multi-stage attack. An attacker performs reconnaissance, gains a foothold, escalates privileges, moves laterally, and finally exfiltrates data. Each step might involve multiple HTTP requests that, individually, seem harmless but are malicious when correlated.

To detect these kinds of threats, our WAF needs a memory. It must be able to link related requests together into a "session" and analyze behavior over time. This brings us to today's learning outcome: Design a session tracking system for stateful WAF inspection and multi-request attack correlation.

We will architect the components needed to identify user sessions, maintain state for each session, and use that state to detect attacks that would be invisible to a stateless inspection engine.

1. The Foundation: What is Session Tracking in a WAF?

In standard web development, a session is typically associated with a logged-in user to maintain application state. In a WAF, the concept is broader and serves a different purpose: security correlation. A WAF session is a sequence of requests from a single client, whether they are authenticated or not.

The goal is to build a profile of activity for each client and use that profile to detect deviations that indicate an attack. Let's explore the formal concepts behind this.

Web Application Firewall Documentation for Developers and Testers

This document from Imperva provides an excellent overview of how a commercial WAF implements stateful inspection. We will use it to understand the core concepts of session and user tracking from a security perspective.

Please read the sections 'Web Application User Tracking' and 'Session Tracking'. Focus on the distinction between the two and the WAF's role in associating a user name with an HTTP session after a successful login.

As the document explains, a WAF's session tracking system serves two primary functions:

  1. Anonymous Session Tracking: It identifies and tracks unique, unauthenticated clients. This is crucial for detecting pre-login attacks like credential stuffing, vulnerability scanning, or content scraping. The WAF uses session identifiers (often cookies) to link requests from the same browser.
  2. Authenticated User Tracking (WAUT): Once a user successfully logs in, the WAF elevates the session state by associating it with a specific application username. This enables the detection of post-login attacks, such as an authenticated user attempting to access another user's data (Broken Access Control) or abuse business logic.

Now, let's architect a system that can provide this capability from first principles.

2. Architecting the Session Tracking System

To build a robust session tracking system, we need three key components: a method to identify sessions on the client side, a high-performance store to maintain state on the server side, and a well-designed data model to hold the session information.

For inspiration, we can look at a parallel system design problem: building a stateful waiting room at the edge. The architectural principles are nearly identical.

Stateful waiting room | Fastly Documentation

This Fastly documentation on building a 'Stateful waiting room' is a fantastic practical guide. While its goal is different, the architecture it describes for tracking individual users in a queue is a perfect blueprint for a WAF's session tracking system.

Please read the 'Instructions' section, then the subsections 'Extract data from cookie' and 'Connect to Redis'. Pay close attention to: The 'ticket system' analogy for tracking users. The use of a signed JWT cookie as a tamper-proof client identifier. The use of Redis as a high-performance, centralized state store.

Drawing from the principles in that guide, let's design our three components.

Component 1: The Session Identifier (Client-Side)

The WAF needs a reliable way to tag a browser so it can recognize it across subsequent requests. While an IP address is a simple identifier, it's not reliable due to NAT, proxies, and dynamic IP assignments. A far more robust method is to use an HTTP cookie.

Our system will work as follows:

  1. When the WAF sees a request from a client for the first time (i.e., no session cookie present), it generates a unique, high-entropy session ID.
  2. It then sets a cookie on the client's browser containing this ID.
  3. On all subsequent requests, the WAF reads this cookie to retrieve the session ID and look up the corresponding state.

Design Consideration: Tamper-Proofing
A simple cookie like Set-Cookie: session_id=12345 is vulnerable. A malicious user could alter it or try to hijack another user's session. To prevent this, we should use a signed token, like a JSON Web Token (JWT), as demonstrated in the Fastly article.

  • The JWT payload contains the session_id and an expiry timestamp.
  • The token is signed with a secret key known only to the WAF.
  • When a request comes in, the WAF first verifies the JWT's signature. If the signature is invalid, it means the cookie has been tampered with, and the WAF can immediately drop the request or flag it as malicious.

Component 2: The Session State Store (Server-Side)

This is the "memory" of our WAF. For every active session ID, we need to store a corresponding data structure. Given that a WAF processes thousands or millions of requests per second, this state store has demanding performance requirements:

  • Low Latency: Lookups must be completed in microseconds to avoid adding significant delay to requests.
  • High Throughput: It must handle a massive volume of concurrent reads and writes.
  • Time-to-Live (TTL): It needs a mechanism to automatically expire and clean up old, inactive sessions.

This profile makes an in-memory key-value store like Redis or Memcached an ideal choice. These databases are designed for exactly this kind of high-speed, ephemeral state management. As seen in the Fastly example, Redis is a popular and powerful choice. The session ID from the cookie becomes the key in Redis.

Component 3: The Session Data Model

What information should we store for each session? This data model is the heart of our stateful engine. It should be rich enough to enable powerful correlation rules.

A robust session data model, stored as the value for a given session ID key in Redis, would look something like this:

{
  "session_id": "uNiQuE-iD-12345",
  "created_at": 1677612345,
  "last_seen_at": 1677612901,
  "source_ip": "8.8.8.8",
  "user_agent": "Mozilla/5.0...",
  "device_fingerprint": "a1b2c3d4...",

  "auth_state": {
    "status": "authenticated",
    "user_id": "alice@example.com",
    "authenticated_at": 1677612600
  },
  
  "anomaly_scores": {
    "cumulative_session_score": 25,
    "last_request_score": 5,
    "high_score_events": ["sql_injection", "xss"]
  },

  "behavioral_counters": {
    "login_failures_last_5m": 2,
    "requests_per_minute": 15,
    "num_404s_last_10m": 3
  }
}

This model provides a 360-degree view of the session, enabling us to write powerful security logic.

3. Applying Session State: Multi-Request Attack Correlation

With our architecture in place (JWT cookie + Redis + rich data model), we can now implement stateful detection rules. This is where the WAF's intelligence truly shines.

The Imperva document (LINK) lists several policy violations that are impossible to detect without state. Let's design the logic for a few common examples.

Example 1: Detecting Slow-Rate Credential Stuffing

A stateless WAF only sees one failed login at a time. A stateful WAF can see the pattern.

  • On Request: A login request to /login.php fails.
  • WAF Logic:
    1. Retrieve session state from Redis using the session ID from the cookie.
    2. Increment the behavioral_counters.login_failures_last_5m counter.
    3. Check a rule: IF session.behavioral_counters.login_failures_last_5m > 10 THEN...
    4. Action: Block the session ID for 15 minutes and add the source IP to a temporary blocklist.

Example 2: Detecting Business Logic Abuse (Cookie/Parameter Tampering)

Imagine a checkout flow where the price is set in a cookie or a read-only form field. A user might try to tamper with it to get a discount.

  • On Request 1 (Page Load): The application server sends the checkout page, setting a cookie: Set-Cookie: item_price=100.00.

  • WAF Logic (Response Path):

    1. The WAF sees this Set-Cookie header in the response.
    2. It identifies item_price as a protected parameter.
    3. It stores this value in the session state in Redis: session.protected_params['item_price'] = '100.00'.
  • On Request 2 (Form Submit): The user submits the form, having modified the cookie to item_price=1.00.

  • WAF Logic (Request Path):

    1. The WAF sees the incoming cookie item_price=1.00.
    2. It retrieves the session state and compares the incoming value to the stored value: '1.00' != '100.00'.
    3. Action: This is a "Cookie Tampering" violation. The WAF blocks the request and flags the session for investigation.

Example 3: Evolving the Anomaly Score

We can extend the anomaly scoring engine from our last lesson to incorporate session context. The score is no longer just per-request; it can accumulate over a session.

  • On Request: A request comes in and our stateless engine gives it an anomaly score of 5 (e.g., for a suspicious user-agent).
  • WAF Logic:
    1. Retrieve session state from Redis.
    2. Update the session score: session.anomaly_scores.cumulative_session_score += 5.
    3. Check a session-level threshold: IF session.anomaly_scores.cumulative_session_score > 50 THEN...
    4. Action: Even if no single request was malicious enough to be blocked, the cumulative "badness" of the session has crossed a threshold. The WAF can now take a stronger action, such as blocking the session or forcing a CAPTCHA challenge.

Conclusion

Today, we've added a critical capability to our WAF architecture: a memory. By designing a stateful session tracking system, we've elevated our WAF from a simple, stateless gatekeeper to an intelligent inspector that understands context.

Key Takeaways:

  • Session tracking is essential for detecting attacks that unfold across multiple requests, such as slow-rate brute force, business logic abuse, and reconnaissance scanning.
  • The core architectural pattern consists of a tamper-proof client-side identifier (like a signed JWT cookie) and a high-performance server-side state store (like Redis).
  • A rich session data model is crucial for effective correlation. It should track not just identity but also authentication state, cumulative risk scores, and behavioral counters.
  • Stateful rules can correlate events over time, turning a series of low-risk, independent events into a single high-confidence security alert.

Preview of the Next Module:

Our work on the WAF architecture is now quite comprehensive. We've designed a modular inspection pipeline, a high-performance signature engine, a nuanced anomaly scoring system, and now a stateful session tracker.

In the next module, we will shift our focus to a different but related security product: Architecting DDoS Mitigation Systems. You'll see how some of the concepts we've discussed, particularly distinguishing legitimate user sessions from automated bot traffic at Layer 7, play a critical role in defending against sophisticated application-layer DDoS attacks.

Can't find a good explanation? Sign up and we'll make it for you

Sign up