A Web Application Firewall (WAF) is a security solution that protects web applications by filtering and monitoring HTTP/HTTPS traffic between clients and the application. Unlike traditional firewalls that operate at the network level, a WAF focuses on the application layer, enabling it to detect and block threats targeting the specific logic of web applications. This includes inspecting and filtering URLs, form inputs, cookies, and other user-generated content.

In addition to basic (rule based) filtering, many WAFs offer advanced features such as IP white- and blacklisting, which allow administrators to explicitly permit or block traffic from specific IP addresses or ranges.

Instead of relying on individual IP addresses or ranges, geofencing capabilities allow you to restrict or allow access based on the geographic location of incoming requests, using an IP address geolocation database. For example, an online retailer might use geofencing to block access from countries where they do not ship products—thereby reducing the risk of fraudulent transactions and minimizing unwanted traffic.

Some WAF solutions include built-in capabilities to inspect incoming requests and uploaded files for known malware signatures or suspicious patterns. This feature helps prevent attackers from uploading malicious files—such as web shells, executable scripts, or trojanized documents—into the application environment.

Advanced WAFs may integrate with antivirus engines or sandboxing technologies to scan files in real-time. When a suspicious or known-malicious file is detected, the WAF can block the request entirely, quarantine the file, or notify security teams depending on the configured policy.

This is especially important in applications that allow file uploads, such as content management systems (CMS), customer support portals, and HR systems. Without proper inspection, such endpoints can become an entry point for remote code execution or lateral movement inside the network.


More broadly, file uploads are just one of many vectors attackers exploit when targeting web applications. Because these applications are exposed to the internet and often include complex, dynamic logic, they are especially vulnerable to a range of attacks—such as SQL injection, cross-site scripting (XSS), remote file inclusion (RFI), and command injection.

A WAF helps prevent these attacks by analyzing incoming traffic and blocking malicious requests before they reach the application. It can also act as a protective layer against zero-day vulnerabilities by using generic filtering rules.

In addition, many WAFs offer enhanced features such as:

  • Data Loss Prevention (DLP)
  • Bot detection and mitigation
  • Malicious behavior analysis
  • Traffic logging and reporting for auditing

WAFs can be deployed in different ways depending on the application environment, network topology, and desired level of control:

  • Network-based WAFs: Deployed at the network edge or integrated at the cloud provider level. Suitable for large-scale environments that require high-throughput filtering and centralized management.

  • Host-based WAFs: Installed directly on the web server or within the application environment. Provide close integration with the application and better context awareness, ideal for smaller or tightly controlled environments.

  • Cloud-based WAFs: Offered as managed services by cloud providers such as AWS, Azure, Cloudflare, and Google Cloud. These are quick to deploy and easy to manage.

Each deployment model has its strengths and trade-offs:

Type Advantages Challenges
Network-based Centralized management May require changes in network architecture
Host-based Application context, lightweight Server overhead, limited scalability
Cloud-based Easy deployment, automatic updates Dependency on third-party provider

Example: Running a WAF with Docker

A practical way to get hands-on experience with a WAF is to run it alongside a web application using Docker. For instance, you can deploy ModSecurity configured with the OWASP Core Rule Set (CRS) — a set of generic attack detection rules maintained by the Open Worldwide Application Security Project — as a reverse proxy in front of a basic Nginx or Node.js application.

Example using ModSecurity with OWASP CRS

# Create a dedicated Docker network
$ docker network create waf-net

# Create and start the web app, ie. echo-server
$ docker run -d \
    --name echo-server \
    --network waf-net \
    -p 9080:80 \
    ealen/echo-server

# Create and start ModSecurity with OWASP Core Rule Set as reverse proxy
$ docker run -d \
  --name modsec-waf \
  --network waf-net \
  -p 8080:8080 \
  -e "BACKEND=http://echo-server" \
  owasp/modsecurity-crs:nginx

To test web application without WAF, you can send malicious payload to http://localhost:9080/?id=<script>alert(1);</script>.

$ curl -s "http://localhost:9080?id=%3Cscript%3Ealert(1)%3B%3C/script%3E" | jq

This sends the URL-encoded payload <script>alert(1);</script> as a query parameter to the application.

If the application does not sanitize or validate the input properly, this payload may be reflected in the response or stored and later executed, demonstrating a potential Cross-Site Scripting (XSS) vulnerability.

{
  "host": {
    "hostname": "localhost",
    "ip": "::ffff:172.22.0.1",
    "ips": []
  },
  "http": {
    "method": "GET",
    "baseUrl": "",
    "originalUrl": "/?id=%3Cscript%3Ealert(1)%3B%3C/script%3E",
    "protocol": "http"
  },
  "request": {
    "params": {
      "0": "/"
    },
    "query": {
      "id": "<script>alert(1);</script>"
    },
    "cookies": {},
    "body": {},
    "headers": {
      "host": "localhost:9080",
      "user-agent": "curl/8.8.0",
      "accept": "*/*"
    }
  },
  "environment": {
    "PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
    "HOSTNAME": "806eab5e17df",
    "NODE_VERSION": "20.11.0",
    "YARN_VERSION": "1.22.19",
    "HOME": "/root"
  }
} 

To test the WAF in action, access your application by navigating to http://localhost:8080. The WAF container acts as a gatekeeper, analyzing incoming requests and blocking malicious traffic before it reaches the echo-server.

$ curl -s "http://localhost:8080?id=%3Cscript%3Ealert(1)%3B%3C/script%3E"

Instead of receiving the echo-server’s normal response, you get an HTTP 403 Forbidden error. This indicates that the WAF has intercepted the request and blocked it due to malicious content.

<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx</center>
</body>
</html>

Requirements for Setting Up the Demo Environment

Further Reading and Resources