Lockdown WordPress with Traefik proxy – No plugins

Published by Okezie on

Your infrastructure ONLY as strong as your weakest link.

TL;DR – See solution in docker compose

I once had a server that was hacked on a DigitalOcean VPS. Having my server hacked was my goal at the time – yeah, just hear me out.

The intention was to understand what happens to a server after it’s been compromized. Purely from an investigative and learning standpoint because it was the first time I had a service publicly exposed. The server ran for about 4 months… nothing. Until I got a notification that Google Chrome was blocking my website due to malicious behavior. I was excited.

I quickly logged in to my server to see if I can piece together what the hacker is using my server for. After looking through some of the config files, I saw blocks of indecipherable PHP code that appeared to be base64 encoded. So I attempted to decode the blocks (it was base64), but they used random variable names that made it difficult to understand what was being done. I got a clearer picture by monitoring incomming requests in nginx to see what was being sent to the server – they were payloads to redirect the user to other websites. Ultimately, they had repurposed my server to be a proxy for an email spam/phishing attack. Requests came from random locations, but there was indication that it originated from user’s email accounts. File modified was primarily index.php.

This post will cover how Traefik can be used to lockdown your wordpress installation. If you have managed a wordpress server, you know that your site gets attacked several thousand times a day. I will go over a few types of attacks and how to mitigate them by using a Traefik proxy in front of your wordpress server.

Assumptions

  • You are an admin on your wordpress server
  • You are able to run Traefik either as a docker container or stand alone service
  • You have installed and configured docker, docker-compose and the apache benchmark tool ab (optional)

Docker compose configuration

Although this post is wordpress specific, the same techniques can be applied to any web service behind a Traefik proxy

For the purpose of condensing all parts of this infrastructure into something easy to deploy and test, I will be using docker compse to encapsulate all the configuration required. Note that this is not a production setup as there are considerations in terms of resilience, security and data persistence that are not accounted for in this docker compose setup – that’s beyond the scope of this post.

The following is a summary of what is being done in the docker-compose file above:

  • Run a wordpress server with a mysql database backend
  • Run a Traefik server that recieves all incomming requests, then routes to the wordpress server
  • Configure Traefik using labels on the containers
    • WordPress:
      • Setup rate limiting – 10 requests per second with an allowed burst of 50 requests per second.
      • Add basic auth to any request with any of these prefixes: /wp-admin, /wp-login.php.
        username: test, password: password
    • Traefik
      • Setup entrypoints where Traefik will listen for requests
      • Enable Traefik dashboard on port 8888
      • Enable access logging

Docker Compose – See it in action

version: '3.1'
services:
  db:
    image: mysql:5.7
    restart: always
    environment:
      MYSQL_DATABASE: exampledb
      MYSQL_USER: exampleuser
      MYSQL_PASSWORD: examplepass
      MYSQL_RANDOM_ROOT_PASSWORD: '1'
    volumes:
      - db:/var/lib/mysql

  wordpress:
    image: wordpress
    restart: always
    environment:
      PORT: 80
      WORDPRESS_DB_HOST: db
      WORDPRESS_DB_USER: exampleuser
      WORDPRESS_DB_PASSWORD: examplepass
      WORDPRESS_DB_NAME: exampledb
    volumes:
      - wordpress:/var/www/html
    labels:
      - "traefik.enable=true"
      - "traefik.http.middlewares.auth-users.basicauth.users=test:$apr1$gkhQMADi$rQ3MBaI0Zbj6p.y62OsIJ."
      - "traefik.http.middlewares.known-ips.ipwhitelist.sourceRange=192.168.1.7,127.0.0.1/32,0.0.0.0/0"
      - "traefik.http.middlewares.wp-ratelimit.ratelimit.average=10"
      - "traefik.http.middlewares.wp-ratelimit.ratelimit.burst=50"
      - "traefik.http.middlewares.secured.chain.middlewares=known-ips,auth-users,wp-ratelimit"
      - "traefik.http.routers.wp_admin.entrypoints=web"
      - "traefik.http.routers.wp_admin.middlewares=secured"
      - "traefik.http.routers.wp_admin.rule=PathPrefix(`/wp-admin`,`/admin`,`/wp-login.php`) || Method(`POST`)"
      - "traefik.http.routers.wp_web.entrypoints=web"
      - "traefik.http.routers.wp_web.middlewares=wp-ratelimit"
      - "traefik.http.routers.wp_web.rule=Host(`localhost`)"

  traefik:
    image: "traefik:v2.2.1"
    container_name: "traefik"
    command:
      # - "--log.level=DEBUG"
      - "--accesslog=true"
      - "--api.insecure=true"
      - "--api.dashboard=true"
      - "--providers.docker=true"
      - "--providers.docker.exposedbydefault=false"
      - "--entrypoints.web.address=:8080"
      - "--entrypoints.traefik.address=:8888"
    labels:
      traefik.enable: true
      traefik.http.routers.traefik.service: api@internal
      traefik.http.routers.traefik.entrypoints: traefik
    ports:
      - "8080:8080"
      - "8888:8888"
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock:ro"

volumes:
  wordpress:
  db:

Observe

  • View traefik logs:
    docker logs -f --tail 10 traefik
  • Send 1000 requests from 10 concurrent http clients:
    ab -n 1000 -c 10 http://localhost:8080/
  • Navigate to http://localhost:8080/wp-admin – You will be prompted with a basic auth prompt. Enter username: test, password: password to authenticate.

Traefik Proxy

Traefik is an open-source Edge Router that makes publishing your services a fun and easy experience. It receives requests on behalf of your system and finds out which components are responsible for handling them.
What sets Traefik apart, besides its many features, is that it automatically discovers the right configuration for your services. The magic happens when Traefik inspects your infrastructure, where it finds relevant information and discovers which service serves which request.

Traefik has native support for docker and routes can be auto configured by defining docker labels that are used to configure Traefik – more on this later.
Read more about Traefik here…

Common WordPress attacks

When dealing with securing any system, it’s usually an excersise in limiting the attack surface of your system. This means limiting the points of penetration exposed to attackers, then securing those entry points. I’ll assume that your server only exposes endponts that absolutely need to be open – like port 22 (ssh) and http ports (80, 443).

WordPress specific attacks target vulnerabilities in PHP, wordpress plugins, compromized wordpress themes, outdated wordpress installations, poorly secured servers with easy to guess ssh username and password, poorly secured FTP servers or even exposed mysql server. Most of these attacks involve sending requests to wp-admin and wp-login.php.

Traefik is used to mitgate the following types of attacks:

  • Brute force wordpress login attempts
  • WordPress admin probes
  • Denial of service

These forms of attack are blocked using the following features in Traefik

  • Basic auth – serves as 2nd form of authentication
  • IP source filtering – You can limit what IP addresses can reach certain endpoints, like wp-admin
  • Rate limiting – Limit abusive requests. a 429 response code is sent when the user exceeds the defined limit.

Conclusion

Obviously this is just one part of locking down your server infrastructure. Observability is a key part of security in order to understand what is happening in your environment. I cannot stress how important it is to have a way to observe your infrastructure. I don’t care what you use, just observe your infrastructure. At least you will need the following:

  • Logging system – collect access logs from your webserver
  • Metrics system – Collect metrics from Traefik and other parts of your infastructure and view time series data from your services. Traefik exposes a Prometheus endpoint.
  • Alerting system – A mechanism to alert you when anomalies are detected

That said, Traefik is an excellent piece of software. Very modern, forward thinking with great features to help secure your infrastructure. It has support for service discovery from consul, docker, kubernetes. Traefik will also automatically manage Let’s Encrypt certificates for your services.

Simple to use software is hard, so I appreciate what the Traefik team have built.

Happy building…