Quickly Integrate Free WAF with Nginx

Lulu - Aug 19 - - Dev Community

OpenResty is a full-fledged web application server based on Nginx and LuaJIT. It offers a powerful and flexible way to build and extend web application servers while maintaining the high performance and reliability of Nginx. OpenResty serves as the foundation for gateway products like APISIX, Kong, and Ingress Nginx, making it an excellent choice as a unified entry point for WAF protection.

In this guide, we'll use the free SafeLine WAF Community Edition. For those interested, you can try it out here:SafeLine Demo.

Image description

This article explains how to enhance OpenResty with security protection using the free SafeLine WAF Community Edition and the lua-resty-t1k plugin, achieving a security architecture that separates forwarding and detection services.

Basic Version

The basic setup involves installing both OpenResty and SafeLine WAF Community Edition on the same host.

Step 1 – Install SafeLine

SafeLine WAF Community Edition offers several installation methods. For detailed instructions, refer to the official documentation.

Step 2 – Configure OpenResty

We'll use the official alpine-fat image of OpenResty as an example to enable SafeLine WAF protection:

First, navigate to the SafeLine WAF installation directory and ensure the resources/detector directory exists. Then, start OpenResty:

docker run -d --name openresty -v $(pwd)/resources/detector:/opt/detector 
openresty/openresty:alpine-fat
Enter fullscreen mode Exit fullscreen mode

Next, enter the OpenResty container and install the lua-resty-t1k plugin using luarocks:

docker exec -it openresty bash
luarocks install lua-resty-t1k
Enter fullscreen mode Exit fullscreen mode

Then, modify the OpenResty configuration located at /etc/nginx/conf.d/default.conf to add the /t path for testing WAF protection. Here's the complete configuration, which can be directly applied to the /etc/nginx/conf.d/default.conf file:

server {
    listen       80;
    server_name  localhost;

    location /t {
        access_by_lua_block {
            local t1k = require "resty.t1k"

            local t = {
                mode = "block",
                host = "unix:/opt/detector/snserver.sock",
            }

            local ok, err, result = t1k.do_access(t, true)
            if not ok then
                ngx.log(ngx.ERR, err)
            end
        }

        header_filter_by_lua_block {
            local t1k = require "resty.t1k"
            t1k.do_header_filter()
        }

        content_by_lua_block {
            ngx.say("passed")
        }
    }

    location / {
        root   /usr/local/openresty/nginx/html;
        index  index.html index.htm;
    }

    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/local/openresty/nginx/html;
    }
}
Enter fullscreen mode Exit fullscreen mode

Finally, validate and reload the OpenResty configuration:

openresty -t && openresty -s reload
Enter fullscreen mode Exit fullscreen mode

Step 3 – Verify

Access /t/shell.php to verify the protection:

curl http://127.0.0.1/t/shell.php
Enter fullscreen mode Exit fullscreen mode

You should see a response like this:

{"code": 403, "success":false, "message": "blocked by Chaitin SafeLine Web Application Firewall", 
"event_id": "2005f374e2c44757a449b1071f284e3b"}
Enter fullscreen mode Exit fullscreen mode

You can also view the corresponding blocking log in the SafeLine WAF Community Edition.

Normal access to /t should not trigger any blocking:

curl http://127.0.0.1/t/
passed
Enter fullscreen mode Exit fullscreen mode

Advanced Version

In a production environment, SafeLine WAF Community Edition might not be on the same host as OpenResty, or there might be multiple OpenResty instances across different hosts. In this case, you need to map the detection service to a specified port on the host so that other hosts can access it via the network.

Locate the SafeLine WAF installation directory and modify the compose.yaml file by adding port mapping to the detector section. Here’s the updated configuration:

detector:
    container_name: safeline-detector
    restart: always
    image: chaitin/safeline-detector:${IMAGE_TAG}
    volumes:
    - ${SAFELINE_DIR}/resources/detector:/resources/detector
    - ${SAFELINE_DIR}/logs/detector:/logs/detector
    - /etc/localtime:/etc/localtime:ro
    environment:
    - LOG_DIR=/logs/detector
    networks:
      safeline-ce:
        ipv4_address: ${SUBNET_PREFIX}.5
    cap_drop:
    - net_raw
    ports: ["8000:8000"] # Newly added line
Enter fullscreen mode Exit fullscreen mode

Next, modify the detection service configuration file resources/detector/snserver.yml as follows:

fusion_sofile: ./config/libfusion2.so
ip_location_db: ./GeoLite2-City.mmdb
# bind_addr: unix:///resources/detector/snserver.sock # Commented out line
bind_addr: 0.0.0.0 # Newly added line
listen_port: 8000 # Newly added line
Enter fullscreen mode Exit fullscreen mode

Apply the configuration changes by running:

docker compose up -d
Enter fullscreen mode Exit fullscreen mode

You can verify that the detection service port is reachable using the nc command:

nc -zv ${SafeLine WAF Community Edition Host IP} 8000
Connection to ${SafeLine WAF Community Edition Host IP} 8000 port [tcp/*] succeeded!
Enter fullscreen mode Exit fullscreen mode

Finally, modify the OpenResty configuration file to specify the host and port. Here’s the updated configuration:

location /t {
    access_by_lua_block {
        local t1k = require "resty.t1k"

        local t = {
            mode = "block",
            host = "${SafeLine WAF Community Edition Host IP}",
            port = 8000,
        }

        local ok, err, result = t1k.do_access(t, true)
        if not ok then
            ngx.log(ngx.ERR, err)
        end
    }

    header_filter_by_lua_block {
        local t1k = require "resty.t1k"
        t1k.do_header_filter()
    }

    content_by_lua_block {
        ngx.say("passed")
    }
}
Enter fullscreen mode Exit fullscreen mode

Validate and reload the OpenResty configuration:

openresty -t && openresty -s reload
Enter fullscreen mode Exit fullscreen mode

Now you can verify the security protection. Enjoy a more secure OpenResty setup!

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .