ModSecurity is a free, open-source, and most popular web application firewall (WAF) that protects your web application against a wide range of Layer 7 attacks. It was designed for Apache web server monitoring, logging, and filtering requests. It comes with a Core Rule Set that detects and stops several attacks including, SQL injection, cross-site scripting, Trojans, bad user agents, session hijacking, and more.

In this tutorial, I will show you how to install ModSecurity 3 with Apache inside a Docker container.

Requirements

  • A server running Ubuntu 20.04.
  • A root password is configured on your server.

Getting Started

First, it is recommended to update your system to the latest version. You can update it with the following command:

apt-get update -y

Once your system is up-to-date, you will need to install some dependencies to your system. You can install all of them with the following command:

apt-get install apt-transport-https ca-certificates curl gnupg2 software-properties-common -y

Once all the dependencies are installed, you can proceed to the next step.

Install Docker

Next, you will need to install the Docker CE to your system. By default, the latest version of Docker is not included in the Ubuntu default repository. So you will need to add the Docker official repository to the APT.

First, download and add the Docker GPG key with the following command:

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add -

Next, add the Docker CE repository to the APT source list with the following command:

echo "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -sc) stable" > /etc/apt/sources.list.d/docker-ce.list

Once the repository is added, update the repository with the following command:

apt-get update -y

Once the repository is updated, install the latest version of Docker CE with the following command:

apt-get install docker-ce -y

After installing Docker CE, verify the installed version of Docker CE with the following command:

docker --version

You should get the following output:

Docker version 20.10.6, build 370c289

You can also check the status of the Docker service with the following command:

systemctl status docker

You should get the following output:

? docker.service - Docker Application Container Engine
     Loaded: loaded (/lib/systemd/system/docker.service; enabled; vendor preset: enabled)
     Active: active (running) since Sun 2021-05-16 06:49:29 UTC; 38s ago
TriggeredBy: ? docker.socket
       Docs: https://docs.docker.com
   Main PID: 8964 (dockerd)
      Tasks: 8
     Memory: 40.6M
     CGroup: /system.slice/docker.service
             ??8964 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock

May 16 06:49:29 ubuntu2004 dockerd[8964]: time="2021-05-16T06:49:29.365433228Z" level=warning msg="Your kernel does not support swap memory li>
May 16 06:49:29 ubuntu2004 dockerd[8964]: time="2021-05-16T06:49:29.365916961Z" level=warning msg="Your kernel does not support cgroup blkio w>
May 16 06:49:29 ubuntu2004 dockerd[8964]: time="2021-05-16T06:49:29.366112111Z" level=warning msg="Your kernel does not support cgroup blkio w>
May 16 06:49:29 ubuntu2004 dockerd[8964]: time="2021-05-16T06:49:29.366653374Z" level=info msg="Loading containers: start."
May 16 06:49:29 ubuntu2004 dockerd[8964]: time="2021-05-16T06:49:29.498790388Z" level=info msg="Default bridge (docker0) is assigned with an I>
May 16 06:49:29 ubuntu2004 dockerd[8964]: time="2021-05-16T06:49:29.576691602Z" level=info msg="Loading containers: done."
May 16 06:49:29 ubuntu2004 dockerd[8964]: time="2021-05-16T06:49:29.610542206Z" level=info msg="Docker daemon" commit=8728dd2 graphdriver(s)=o>
May 16 06:49:29 ubuntu2004 dockerd[8964]: time="2021-05-16T06:49:29.611668583Z" level=info msg="Daemon has completed initialization"
May 16 06:49:29 ubuntu2004 systemd[1]: Started Docker Application Container Engine.
May 16 06:49:29 ubuntu2004 dockerd[8964]: time="2021-05-16T06:49:29.690496888Z" level=info msg="API listen on /run/docker.sock"
lines 1-21/21 (END)

Once you are finished, you can proceed to the next step.

Create a Dockerfile for ModSecurity

Next, you will need to create a Dockerfile to install the ModSecurity inside the Ubuntu container.

First, change the directory to the /opt and create a modsec_rules.conf file with the following command:

cd /opt

nano modsec_rules.conf

Add the following lines:

Include "https://www.howtoforge.com/etc/apache2/modsecurity.d/modsecurity.conf"
Include "https://www.howtoforge.com/etc/apache2/modsecurity.d/owasp-crs/crs-setup.conf"
Include "https://www.howtoforge.com/etc/apache2/modsecurity.d/owasp-crs/rules/*.conf"

Save and close the file then create another file with the following command:

nano 000-default.conf

Add the following lines:

	modsecurity on
	modsecurity_rules_file /etc/apache2/modsecurity.d/modsec_rules.conf 
	ServerAdmin [email protected]
	DocumentRoot /var/www/html
	ErrorLog ${APACHE_LOG_DIR}/error.log
	CustomLog ${APACHE_LOG_DIR}/access.log combined

Save and close the file when you are finished. Dockerfile will copy the above files to the Docker container during the build process.

Finally, create a Dockerfile with the following command:

nano Dockerfile

Add the following lines:

# Install Modsecurity in a Docker container;
FROM ubuntu:latest
ARG DEBIAN_FRONTEND=noninteractive
# update/upgrade your system
RUN apt-get update -y

# Install Required Dependencies
RUN apt-get install -y g   flex bison curl apache2-dev 
	doxygen libyajl-dev ssdeep liblua5.2-dev 
	libgeoip-dev libtool dh-autoreconf 
	libcurl4-gnutls-dev libxml2 libpcre  -dev 
	libxml2-dev git wget tar apache2

# Download LibModsecurity 
RUN wget https://github.com/SpiderLabs/ModSecurity/releases/download/v3.0.4/modsecurity-v3.0.4.tar.gz

# Extract the Downloaded File
RUN tar xzf modsecurity-v3.0.4.tar.gz && rm -rf modsecurity-v3.0.4.tar.gz

# Compile and Install LibModsecurity
RUN cd modsecurity-v3.0.4 && 
	./build.sh && ./configure && 
	make && make install

# Install ModSecurity-Apache Connector
RUN cd ~ && git clone https://github.com/SpiderLabs/ModSecurity-apache

RUN cd ~/ModSecurity-apache && 
	./autogen.sh && 
	./configure --with-libmodsecurity=/usr/local/modsecurity/ && 
	make && 
	make install

# Load the Apache ModSecurity Connector Module
RUN echo "LoadModule security3_module /usr/lib/apache2/modules/mod_security3.so" >> /etc/apache2/apache2.conf

# Configure ModSecurity
RUN mkdir /etc/apache2/modsecurity.d && 
	cp modsecurity-v3.0.4/modsecurity.conf-recommended /etc/apache2/modsecurity.d/modsecurity.conf && 
	cp modsecurity-v3.0.4/unicode.mapping /etc/apache2/modsecurity.d/ && 
	sed -i 's/SecRuleEngine DetectionOnly/SecRuleEngine On/' /etc/apache2/modsecurity.d/modsecurity.conf
ADD modsec_rules.conf /etc/apache2/modsecurity.d/

# Install OWASP ModSecurity Core Rule Set (CRS) on Ubuntu
RUN git clone https://github.com/SpiderLabs/owasp-modsecurity-crs.git /etc/apache2/modsecurity.d/owasp-crs && 
	cp /etc/apache2/modsecurity.d/owasp-crs/crs-setup.conf.example /etc/apache2/modsecurity.d/owasp-crs/crs-setup.conf

# Activate ModSecurity
RUN mv /etc/apache2/sites-available/000-default.conf /etc/apache2/sites-available/000-default.conf.old
ADD 000-default.conf /etc/apache2/sites-available/

EXPOSE 80
CMD apachectl -D FOREGROUND

Save and close the file when you are finished.

The above file will download the Ubuntu image, install all the dependencies, download the ModSecurity, compile it, and configure Apache to work with ModSecurity.

At this point, Dockerfile is ready. You can now proceed to the next step.

Build the Apache ModSecurity Image and Start the Container

Now, change the directory to the /opt and build the Docker image for Apache ModSecurity with the following command:

cd /opt

docker build .

Once the build process has been completed, you should get the following output:

Step 13/17 : RUN git clone https://github.com/SpiderLabs/owasp-modsecurity-crs.git /etc/apache2/modsecurity.d/owasp-crs && 	cp /etc/apache2/modsecurity.d/owasp-crs/crs-setup.conf.example /etc/apache2/modsecurity.d/owasp-crs/crs-setup.conf
 ---> Running in 00dfa2a5cd23
Cloning into '/etc/apache2/modsecurity.d/owasp-crs'...
Removing intermediate container 00dfa2a5cd23
 ---> b38c1d874d2f
Step 14/17 : RUN mv /etc/apache2/sites-available/000-default.conf /etc/apache2/sites-available/000-default.conf.old
 ---> Running in 12c9e6d2c559
Removing intermediate container 12c9e6d2c559
 ---> 899e26019297
Step 15/17 : ADD 000-default.conf /etc/apache2/sites-available/
 ---> eb11751afd6c
Step 16/17 : EXPOSE 80
 ---> Running in 2f4ba47e2b66
Removing intermediate container 2f4ba47e2b66
 ---> dd59b0ac7c7c
Step 17/17 : CMD apachectl -D FOREGROUND
 ---> Running in 98b8cc77df0f
Removing intermediate container 98b8cc77df0f
 ---> f603dbc38018
Successfully built f603dbc38018

You can now list all docker images using the following command:

docker images

You should get the following output:

REPOSITORY   TAG       IMAGE ID       CREATED          SIZE
    f603dbc38018   32 seconds ago   2.48GB
ubuntu       latest    7e0aa2d69a15   3 weeks ago      72.7MB

Now, pick the first image id from the above output and start the Apache ModSecurity container with the following command:

docker run --name modsec-apache -ditp 80:80 f603dbc38018

You should get the following output:

40eb0e77e61635c3cee2bfaffbd9489bc7d20aa3e1befb52749de079aaadb528

You can now verify the running container with the following command:

docker ps

You should get the following output:

CONTAINER ID   IMAGE          COMMAND                  CREATED          STATUS          PORTS                               NAMES
40eb0e77e616   f603dbc38018   "https://www.howtoforge.com/bin/sh -c 'apachec…"   17 seconds ago   Up 15 seconds   0.0.0.0:80->80/tcp, :::80->80/tcp   modsec-apache

As you can see, the ModSecurity container is started and listening on port 80.

Verify ModSecurity

At this point, the ModSecurity container is running. Now, it’s time to test whether the ModSecurity rules block the malicious requests or not.

To do so, open your terminal and run the following command:

curl localhost?doc=/bin/ls

You should see the following output:


403 Forbidden

Forbidden

You don't have permission to access this resource.


Apache/2.4.41 (Ubuntu) Server at localhost Port 80

You should see the “403 Forbidden” error. Because ModSecurity has blocked the above request.

You can also check the Apache log for more information.

To do so, first, connect to the container with the following command:

docker exec -it modsec-apache /bin/bash

Once you are connected, you should get the following shell:

[email protected]:/#

Now, check the Apache log with the following command:

tail -f /var/log/apache2/error.log

You should see that ModSecurity has blocked the malicious request:

[Sun May 16 07:24:54.456327 2021] [mpm_event:notice] [pid 15:tid 140204464299072] AH00489: Apache/2.4.41 (Ubuntu) configured -- resuming normal operations
[Sun May 16 07:24:54.456352 2021] [core:notice] [pid 15:tid 140204464299072] AH00094: Command line: '/usr/sbin/apache2 -D FOREGROUND'
[Sun May 16 07:25:36.680515 2021] [:error] [pid 16:tid 140204216108800] [client 172.17.0.1:45298] ModSecurity: Warning. Matched "Operator `PmFromFile' with parameter `unix-shell.data' against variable `ARGS:doc' (Value: `/bin/ls' ) [file "https://www.howtoforge.com/etc/apache2/modsecurity.d/owasp-crs/rules/REQUEST-932-APPLICATION-ATTACK-RCE.conf"] [line "496"] [id "932160"] [rev ""] [msg "Remote Command Execution: Unix Shell Code Found"] [data "Matched Data: bin/ls found within ARGS:doc: /bin/ls"] [severity "2"] [ver "OWASP_CRS/3.2.0"] [maturity "0"] [accuracy "0"] [tag "application-multi"] [tag "language-shell"] [tag "platform-unix"] [tag "attack-rce"] [tag "paranoia-level/1"] [tag "OWASP_CRS"] [tag "OWASP_CRS/WEB_ATTACK/COMMAND_INJECTION"] [tag "WASCTC/WASC-31"] [tag "OWASP_TOP_10/A1"] [tag "PCI/6.5.2"] [hostname "172.17.0.2"] [uri "https://www.howtoforge.com/"] [unique_id "162114993662.860969"] [ref "o1,6v10,7t:urlDecodeUni,t:cmdLine,t:normalizePath,t:lowercase"]

Conclusion

Congratulations! you have successfully installed ModSecurity inside Docker container. I hope you have now enough knowledge to implement this solution in the Docker environment. Feel free to ask me if you have any questions.