Traefik plugin to proxy requests to owasp/modsecurity-crs:apache container

Traefik Modsecurity Plugin

Demo

Traefik plugin to proxy requests to owasp/modsecurity-crs:apache

Github Actions Go Report Go Version Latest Release

Demo

Demo with WAF intercepting relative access in query param.

Demo

Full Configuration with docker-compose

version: "3.7"

services:
  traefik:
    image: traefik
    ports:
      - "8000:80"
      - "8080:8080"
    command:
      - --api.dashboard=true
      - --api.insecure=true
      - --pilot.token=$TRAEFIK_PILOT_TOKEN
      - --experimental.localPlugins.traefik-modsecurity-plugin.moduleName=github.com/acouvreur/traefik-modsecurity-plugin
      - --providers.docker=true
      - --entrypoints.http.address=:80
    volumes:
      - '/var/run/docker.sock:/var/run/docker.sock'
      - '.:/plugins-local/src/github.com/acouvreur/traefik-modsecurity-plugin'
    environment:
      - TRAEFIK_PILOT_TOKEN
    labels:
      - traefik.enable=true
      - traefik.http.services.traefik.loadbalancer.server.port=8080
      - traefik.http.middlewares.waf.plugin.traefik-modsecurity-plugin.modSecurityUrl=http://waf:80

  waf:
    image: owasp/modsecurity-crs:apache
    environment:
      - PARANOIA=1
      - ANOMALY_INBOUND=10
      - ANOMALY_OUTBOUND=5
      - BACKEND=http://dummy

  dummy:
    image: containous/whoami

  website:
    image: containous/whoami
    labels:
      - traefik.enable=true
      - traefik.http.routers.website.rule=PathPrefix(`/website`)
      - traefik.http.routers.website.middlewares=waf@docker
  1. docker-compose up
  2. Go to http://localhost:8000/website, the request is received without warnings
  3. Go to http://localhost:8000/website?test=../etc, the request is intercepted and returned with 403 Forbidden by owasp/modsecurity

How ?

This is a very simple plugin that proxies the query to the owasp/modsecurity apache container.

The plugin checks that the response from the waf container hasn't an http code > 400 before forwarding the request to the real service.

If it is > 400, then the error page is returned instead.

The dummy service is created so the waf container forward the request to a service and respond with 200 OK all the time.

Owner
Alexis Couvreur
Full-stack Engineer. Graduated Master 2 IFI : Software Architecture @ Polytech Nice Sophia-Antipolis, France
Alexis Couvreur
Comments
  • fail to send HTTP request to modsec

    fail to send HTTP request to modsec

    Hello there,

    I have notice that very randomly, traefik is not able to call the modsec plugin, even though it works most of the time. Honestly I'm not really sure what could trigger that. Here is the traefik log that shows the issue:

    fail to send HTTP request to modsec: Get "http://owasp-modsec.default.svc.cluster.local:80/de": context deadline exceeded (Client.Timeout exceeded while awaiting headers)
    

    I did a load test (with very little users, just to have a constant load to try to trigger that error), and the load test was going well, the modsec was doing it's job correctly, but for a duration of 2 seconds in the middle of the loadtest, these errors appeared.

    I searched a bit on traefik issues if I could find anything related to that, and all I could find in a couple issues is that:

    the error context deadline exceeded comes because your plugin takes more than 5s to load.

    Also, during the duration of "failure", modsec container does not show any log, which also shows that traffic is not reaching to it. The problem does not only appear during loadtest but also randomly during the day with "normal" requests.

    Would you have any clue what could be causing that? I hope it's the right place to ask.

  • "body max limit reached: http: request body too large" since 1.2.0

    Hello,

    Since I updated to 1.2.0, a simple post request (not uploading files) gives this error message: body max limit reached: http: request body too large

    Reverting to 1.1.0 fixes the problem.

  • Limit body buffering to avoid resource exhaustion

    Limit body buffering to avoid resource exhaustion

    This PR implement a limit for body buffering in order to avoid resource exhaustion using a very large body (see #7). The default limit is 10MB (which should be enough for non-uploads requests), but it's configurable.

  • feat: hide internal information in case of error

    feat: hide internal information in case of error

    Currently, your plugin displays the error message returned by the go library when it fails to reach the modsecurity container.

    This approach is interesting for debugging and it facilitates the setup of the plugin.

    However, it also reveals information about the internal architecture that should remain hidden.

    As an example, the message below reveals that I'm using kubernetes, that my modsecurity pod is deployed in my kube-system namespace, and that my CIDR looks like 172.20.X.X

    image

    By reading the source code of traefik and some other plugins, I see that it is more common to log the information and return only an HTTP error code without details.

    So I propose a very simple modification here and I open the discussion.

    Thanks in advance and thx for your time.

    Signed-off-by: Benjamin Chenebault [email protected]

  • fix: copy response into reply

    fix: copy response into reply

    Right now, the plugin send back the whole response in the body from Modsec, not only the response body. We are seeing other stuff like headers in the body.

    HTTP/1.1 404 Not Found
    Content-Length: 13238
    Connection: keep-alive
    Content-Type: text/html
    Date: Thu, 30 Dec 2021 14:32:50 GMT
    Etag: "613f2f21-33b6"
    Server: nginx
    
    <!DOCTYPE html>
    <html lang="en">
    

    With this fix we copy the headers, status and body to the response. That way we can have the real Modsec reponse in the browser (body+headers+status).

    Example for me: image

    VS

    image

  • Resource exhaustion via crafted body

    Resource exhaustion via crafted body

    Here the code is reading the body of the request: https://github.com/acouvreur/traefik-modsecurity-plugin/blob/19cdb477b8cee1966ad95278d168ae90a93df663/modsecurity.go#L63

    The problem of this technique is that an attacker can issue a request using an arbitrary body size (1 terabyte) and crash the server, creating a Denial-of-Service.

    A possible mitigation is reading the body while using http.MaxBytesReader() function, to limit the maximum body size. Possibly, the maximum size should be configurable.

    I'm not aware of any other solution (with this middleware architecture, see https://github.com/acouvreur/traefik-modsecurity-plugin/issues/2#issuecomment-1205788329).

  • Add support for configurable timeout

    Add support for configurable timeout

    Hi, I have some use cases where the backend responds in several seconds (e.g. it is building a zip file).

    This PR allows to set a timeout in the config and uses it instead of the hardcoded value of 2 seconds.

  • Saving Keepass database is impossible

    Saving Keepass database is impossible

    Hello when I try to save my keepass database with the waf middleware in traefik it fails. I'm getting an error. If I disable the middleware it's ok. Can you check on it ? I can help with specific test.

  • [Configuration] Modsecurity / Authelia

    [Configuration] Modsecurity / Authelia

    Hello there, I am not sure if this or main plugin is correct place to ask about it but as Authelia is more of docker/traefik thing I will ask here.

    I am having an issue with running this plugin, traefik, modsecurity and authelia together. They all seem to work fine but once modsecurity is added to the mix it seems to be blocking Authelia login page. The page loads but will always show incorrect username/password for the user as modsecurity is denying the request with method not allowed error:

    - - [11/Oct/2022:11:28:43 +0000] "POST /api/firstfactor HTTP/1.1" 405 150 "https://auth.example.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:105.0) Gecko/20100101 Firefox/105.0" "-"

    From what I see the defauly ModSecurity config allows the POSt method. Does anyone use this combo of applications or might be able to help me what setting would I need to allow for Authelia to work? Once logged in and modsecurity enabled then there seem be no issue, just the login page.

  • return 403 for blocked request

    return 403 for blocked request

    Hi, thanks for your work, it's working great. I'm just curious why blocked requests get a response with the code 200. Only the body tells you, that the request resulted in a 403. I would expect that a blocked request gets a 403-response. Is this a design choice or are there technical difficulties in bypassing the http code?

    current state:

    $ http get "http://localhost:8000/website?path=../etc"
    ... 200 OK ...
    

    expectation:

    $ http get "http://localhost:8000/website?path=../etc"
    ... 403 forbidden ...
    

    Thanks:) Lukas

  • 500 error for big request body without files

    500 error for big request body without files

    I'm not sure if the plugin is causing this, or if it's the owasp container. That's why I opened the same issue on the owasp container: https://github.com/coreruleset/modsecurity-crs-docker/issues/85

    I have a form which submits base64 images, so the request body size is somewhere in the 8Mb. On the owasp container, If I don't specify MODSEC_REQ_BODY_NOFILES_LIMIT with a big number, then I will see the modsec rule 200002 to fire. If I specify MODSEC_REQ_BODY_NOFILES_LIMIT with a big enough number (25Mb in my case), the modsec container will not show any errors, however my page will display a 500 Internal Server Error.

    If I don't use modsec at all, my page does not show any error. Would anyone have a clue why this is happening?

    To be clear, I'm not uploading files, just big text body content.

    The reason I'm also posting here, is because the rule will correctly fire if I leave its default value of 128Kb. So I assume it can correctly handle such big request body. So if it can handle it, it must fail somewhere else I would guess. And when the rule correctly fires, I still see a 500 error on my webpage, so I assume there is still something wrong going on somewhere

    I am using the plugin in its version 1.2.1, with maxBodySize: 26214400 I also tried version 1.1.0 with the same result

  • Bypass using bogus Upgrade headers

    Bypass using bogus Upgrade headers

    I see that the middleware is ignoring websocket requests here: https://github.com/acouvreur/traefik-modsecurity-plugin/blob/19cdb477b8cee1966ad95278d168ae90a93df663/modsecurity.go#L56

    Why is that? A request for WebSocket is actually a valid HTTP request, which may contains spurious/malicious data.

    Also, there is another problem with this technique: an attacker can send a Upgrade header while issuing a normal request to any web page, as the server can ignore the Upgrade header for any reason (e.g. no websocket is expected?) and continue to process the request as if the header does not exists. Which means that an attacker can add the Upgrade header to any request to bypass the security check.

    I didn't test the code with WebSockets, so I don't know if there is any issue (probably something with the body?). In that case I propose two possible solutions:

    1. have a configuration parameter where WebSocket endpoints can be specified; or
    2. when a websocket is detected, the body buffering is skipped, and the request to the mod-security backend will be made without body

    The 2nd solution is less secure, as we're still skipping the body in presence of an header, but we don't know if there is any WebSocket or not. So I prefer the 1st.

    I may contribute in few weeks if you like, I'm quite busy at the moment :-)

Traefik - Traefik with zitifed prometheus metrics
Traefik - Traefik with zitifed prometheus metrics

Traefik (pronounced traffic) is a modern HTTP reverse proxy and load balancer th

Jan 17, 2022
Traefik proxy plugin to extract HTTP header value and create a new header with extracted value

Copy header value Traefik plugin Traefik plugin that copies HTTP header value with format key1=value1; key2=value2 into a new header. Motivation for t

May 26, 2022
Developing a Traefik plugin using golang

Developing a Traefik plugin Traefik plugins are developed using the Go language. A Traefik middleware plugin is just a Go package that provides an htt

Nov 21, 2021
Header Block is a middleware plugin for Traefik to block request and response headers which regex matched by their name and/or value

Header Block is a middleware plugin for Traefik to block request and response headers which regex matched by their name and/or value Conf

May 24, 2022
Developing a Traefik plugin with golang

Developing a Traefik plugin Traefik plugins are developed using the Go language. A Traefik middleware plugin is just a Go package that provides an htt

Dec 16, 2021
Log4Shell is a middleware plugin for Traefik which blocks JNDI attacks based on HTTP header values.

Log4Shell Mitigation Log4Shell is a middleware plugin for Traefik which blocks JNDI attacks based on HTTP header values. Related to the Log4J CVE: htt

Dec 20, 2022
Splicetraefikplugin - Sample traefik plugin using golang

Developing a Traefik plugin Traefik plugins are developed using the Go language.

Feb 2, 2022
Validator for your Traefik Proxy configuration
Validator for your Traefik Proxy configuration

Traefik Config Validator Note This is currently pre-release software. traefik-config-validator is a CLI tool to (syntactically) validate your Traefik

Nov 8, 2022
apache dubbo gateway,L7 proxy,virtual host,k8s ingress controller.
apache dubbo gateway,L7 proxy,virtual host,k8s ingress controller.

apache dubbo gateway,L7 proxy,virtual host,k8s ingress controller.

Jul 22, 2022
A server that proxies requests and uses fhttp & my fork of CycleTLS to modify your clienthello and prevent your requests from being fingerprinted.

TLS-Fingerprint-API A server that proxies requests and uses my fork of CycleTLS & fhttp (fork of net/http) to prevent your requests from being fingerp

Jan 7, 2023
A Caddy v2 plugin to track requests in Pirsch analytics

caddy-pirsch-plugin A Caddy v2 plugin to track requests in Pirsch Analytics. Usage pirsch [<matcher>] { client_id <pirsch-client-id> client_se

Sep 15, 2022
A service to proxy requests to a given backend service.

Proxy Service A service to proxy requests to a given backend service. Go 1.17+ Clone git clone [email protected]:janu-cambrelen/proxy-service.git Run (L

Jan 5, 2022
Mar 21, 2022
This is a tool that will proxy simple HTTPS requests to an external HTTP endpoint
 This is a tool that will proxy simple HTTPS requests to an external HTTP endpoint

AcmeShield A secured HTTP proxy that forwards requests from a remote service(Postman). This is a tool that will proxy simple HTTPS requests to an exte

Mar 21, 2022
Traefik Docker Protector

Traefik Docker Protector Limit traefik's control over the docker daemon Traefik

Nov 25, 2022
A TCP proxy used to expose services onto a tailscale network without root. Ideal for container environments.

tailscale-sidecar This is barely tested software, I don't guarantee it works but please make an issue if you use it and find a bug. Pull requests are

Dec 30, 2022
The plugin serves as a starting point for writing a Mattermost plugin

Plugin Starter Template This plugin serves as a starting point for writing a Mattermost plugin. Feel free to base your own plugin off this repository.

Dec 10, 2021
Feb 10, 2022
Cf-cli-find-app-plugin - CF CLI plugin to find applications containing a search string

Overview This cf cli plugin allows users to search for application names that co

Jan 3, 2022