Skip to content

[BUG] Custom ModSecurity rules matching REQUEST_HEADERS fail under HTTP/3 #3298

@blekmus

Description

@blekmus

What happened?

When HTTP/3 is enabled in BunkerWeb, ModSecurity does not receive any request header values (such as Host, :authority, or SERVER_NAME). Because these variables are empty, any custom ModSecurity rules or chains that rely on matching headers will fail to trigger.

For example, I was trying to write a custom rule to disable specific CRS checks for a GraphQL endpoint on a specific domain:

CUSTOM_CONF_MODSEC_CRS_graphql: |
  SecRule REQUEST_FILENAME "@rx ^/api/graphql$" "id:12001,phase:1,nolog,ctl:ruleRemoveById=932100,chain"
  SecRule REQUEST_HEADERS:Host "@rx ^example\.com$" "nolog"

This rule works perfectly under HTTP/2. However, under HTTP/3, the second chain check fails because REQUEST_HEADERS:Host has no value assigned to it.

While Nginx is clearly receiving and processing the HTTP/3 QUIC headers, it appears these headers are not being mapped to the ModSecurity request header variables during the handoff. Interestingly, REQUEST_FILENAME still populates correctly, but the headers do not.

How to reproduce?

Enable HTTP/3. Add a custom ModSecurity rule designed to log header variables to test the mapping. Here's what I used.

SecRule REQUEST_FILENAME "@rx ^/api/graphql$" \
  "id:99999,phase:1,pass,log,msg:'Host=%{REQUEST_HEADERS.Host} Authority=%{REQUEST_HEADERS.:authority} Server=%{SERVER_NAME}'"

Send request to https://example.com/api/graphql. Then check the BunkerWeb logs. You will see that the variables in the msg output are completely empty.

Failing Output (HTTP/3):

Host, Authority, and Server are completely empty inside the [msg "..."] block.

[warn] 3530#3530: *3019 ModSecurity: Warning. Matched "Operator `Rx' with parameter `^/api/graphql$' against variable `REQUEST_FILENAME' (Value: `/api/graphql' ) [msg "Host= Authority= Server="] [hostname "example.com"], server: example.com, request: "POST /api/graphql HTTP/3.0"

Expected/Working Output (HTTP/2):

The exact same rule correctly logs the variables.

[warn] 194#194: *143 ModSecurity: Warning. Matched "Operator `Rx' with parameter `^/api/graphql$' against variable `REQUEST_FILENAME' (Value: `/api/graphql' ) [msg "Host=example.com Authority= Server=example.com"] [hostname "example.com"], server: example.com, request: "POST /api/graphql HTTP/2.0"

Configuration file(s) (yaml or .env)

services:
  bunkerweb:
    image: bunkerity/bunkerweb:1.6.8
    ports:
      - "80:8080/tcp"
      - "443:8443/tcp"
      - "443:8443/udp" 
    environment:
      <<: *bw-env
    restart: "unless-stopped"
    networks:
      - bw-universe
      - bw-services
 
  bw-scheduler:
    image: bunkerity/bunkerweb-scheduler:1.6.8
    environment:
      <<: *bw-env
      BUNKERWEB_INSTANCES: "bunkerweb"
      MULTISITE: "yes"
      USE_WHITELIST: "yes"
      SERVER_NAME: "example.com"
      USE_REVERSE_PROXY: "yes"
      REVERSE_PROXY_URL: "/"
      AUTO_LETS_ENCRYPT: "yes"
      SEND_ANONYMOUS_REPORT: "no"
      SERVE_FILES: "no"
      USE_CLIENT_CACHE: "yes"
      USE_GZIP: "yes"
      DISABLE_DEFAULT_SERVER: "yes"
      USE_REDIS: "yes"
      REDIS_HOST: "bw-redis"
      USE_BROTLI: "yes"
      USE_DNSBL: "yes"
      API_ENABLED: "yes"

      #--------------------------------------------
      USE_MODSECURITY_GLOBAL_CRS: "yes"

      # example.com 
      CUSTOM_CONF_MODSEC_CRS_graphql: |
        SecRule REQUEST_FILENAME "@rx ^/api/graphql$" "id:12001,phase:1,nolog,ctl:ruleRemoveById=932100,chain"
  SecRule REQUEST_HEADERS:Host "@rx ^example\.com$" "nolog"

      example.com_REVERSE_PROXY_HOST: "http://172.17.0.1:5555"
    restart: "unless-stopped"
    networks:
      - bw-db
      - bw-universe

BunkerWeb version

1.6.8

What integration are you using?

Docker

Linux distribution (if applicable)

Ubuntu Server 22.04

Removed private data

  • I have removed all private data from the configuration file and the logs

Code of Conduct

  • I agree to follow this project's Code of Conduct

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions