Skip to content

Implementing FEA409 - Protect Application with Web Application Firewall

Document Implementing FEA409 - Protect Application with Web Application Firewall
Author: Noora Kuikka
Version: 1.0
Date: 11.04.2024

Description

In order to protect the Tukko application from threats such as SQL injection, cross-site scripting (XSS), cross-site request forgery (CSRF) and other common vulnerabilities, we have been tasked with setting up a web application firewall (WAF). After researching various options available, we decided on a dockerized solution utilizing the Nginx web server and the ModSecurity firewall. Below we will briefly describe each component:

Nginx: primarily used as a web server to serve static content such as HTML, CSS or JavaScript; Nginx can also act as a reverse proxy server, receiving requests from clients and forwarding them to backend servers. The Tukko application already utilizes Nginx to serve the frontend files to the web.

ModSecurity: is an open-source web application firewall module that can be deployed with the Apache HTTP Server, Nginx, or IIS web servers. It provides real-time monitoring and protection against a wide range of web application attacks. It has a highly customizable ruleset that includes protection against the OWASP top 10 vulnerabilities and comes with detailed logging capabilities.

When used together, Nginx will act as a reverse proxy server deployed in front of the Tukko web application in order to intercept incoming HTTP requests from clients, and forward them to the backend server. ModSecurity will operate as a WAF module within Nginx, and will intercept the traffic passing through Nginx and apply security rules to analyze and detect potential threats - thus providing an additional layer of security to the Tukko application once deployed.

Prerequisites

Before beginning implementation, the following must be installed and updated to the latest version:

  • Docker
  • Docker Compose

Additionally ensure that the server(s) are up-to-date by running sudo apt update && apt upgrade.

Implementation

1. Creating the reverse proxy docker network

The network used by the reverse proxy to connect to the containers will be used by several different services, therefore it is best to create it separately. We can do this by running the docker command:

docker network create reverse-proxy

Which will create a docker network with the name "reverse-proxy" that the Tukko application containers can connect to.

Creating network for reverse proxy

2. Setup Nginx with ModSecurity Web Application Firewall

The free Nginx docker image does not include the ModSecurity module by default, which led us to believe that we would need to build a new custom docker image. Luckily after a bit of searching, we discovered that OWASP has provided their own Docker image with Nginx, ModSecurity and the core rule set packaged together. This can be downloaded from here.

However for our purposes we will create a docker compose file which will automatically create the correct container and conncet to the reverse-proxy network we created earlier in order to communicate with the Tukko containers that it will be proxying requests for. It will also setup a volume binds to allow the proxy configuration to be managed in a file called proxy.conf.

3. Set contents of compose.yaml file

The contents of the Docker compose file can be seen below:

version: '3.3' 

services:
    reverseproxy:
        container_name: reverse-proxy-nginx
        ports:
            - '80:80'
        volumes:
            - ~/docker/reverse-proxy-nginx/volumes/proxy.conf:/etc/nginx/conf.d/proxy.conf:ro
        environment:
            - PROXY=1
        restart: always
        image: owasp/modsecurity-crs:nginx-alpine
        networks:
            reverse-proxy:
                aliases:
                    - reverse-proxy-nginx
networks:
    reverse-proxy:
        external: true

We created a new ModSecurity directory inside the project with the compose.yaml file including the above configuration.

Compose YAML file contents

4. Set contents of proxy.conf file

Before building the container, we also need to define the proxy configuration. Create a new file called proxy.conf located under ~/docker/reverse-proxy-nginx/volumes

Add the following rules to the file:

server {
    listen 80;

    # This is the IP address of the server where Nginx is running
    server_name 193.167.189.21;

    location / {
        # Tukko container IP or name
        proxy_pass http://172.17.0.2:5173;

        # Include necessary proxy parameters
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        # We add a proxy_read_timeout to prevent issues with WebSocket or long-standing connections
        proxy_read_timeout 90;

        # Optionally, you might need to handle WebSockets
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}

Proxy configuration file

5. Building the Nginx container with ModSecurity

From the same directory containing the compose.yaml file, run the command:

docker-compose up -d

building nginx container

This will build and start the container. Ensure that all containers are on the same network and are accessible with the following commands:

docker inspect <name of tukko container> -f '{{ json .NetworkSettings.Networks }}'

docker inspect <name of nginx container> -f '{{ json .NetworkSettings.Networks }}'

You can also try to ping the tukko container from nginx using:

docker exec <name of nginx container> ping <name or IP address of tukko container>

Testing container network accessibility with ping

6. Running a quick test with fake SQL injection

To quickly see the web application firewall in action, we can send a request with a pattern resembling a SQL injection targeting the Tukko web server using curl:

curl 'http://193.167.189.21/?param=%27%20OR%20%271%27=%271'

Using curl to trigger SQL injection protection

As can be seen from the above screenshot, this returns us the "403 Forbidden" error and logs the attempt in the ModSecurity log files.

Sources

Source Description
OWASP OWASP official website
OWASP ModSecurity Docker Container Official OWASP ModSecurity CRS Docker container
Setup Nginx & ModSecurity in Docker Instructions for setting up Nginx as a reverse proxy with ModSecurity in Docker
Docker Compose Docker Compose documentation
ModSecurity Official ModSecurity GitHub repository
NGINX NGINX official website