Middleware ipWhitelist not working properly?

Hello everyone,

I am facing a major problem that I cannot quite understand so I hope someone will be able to explain it to me.

I am running multiple services via Docker and expose them with traefik (e. g. via URL scheme app1.mydomain.com).
mydomain.com is pointing to my router's public IP address and port forwarding to the server hosting traefik is enabled.
So far, everything is working fine and I can access my application app1 over the Internet.

Now, I want to restrict access for a second application app2 so that it is accessible via app2.mydomain.com but from my LAN only. In order to do that, I created custom DNS entries in my Adguard Home and routed them to my traefik's server IP. In traefik, I configured an ipWhitelist middleware with the sourceRange 192.168.178.0/24 and attached it to the router of app2.

If I use Google Chrome on my Android phone with WiFi enabled, the request succeeds.
If I use Google Chrome on my Android phone with WiFi disabled, the request fails (as expected) with a 403 Forbidden.

Now here's the thing that I don't understand:
If I use a different browser (Brave) on my Android phone with Wifi disabled, the request succeeds! How is this possible? For me, this is a major security implicaiton as I have been hosting sensitive services this way and it seems they were somehow accessible via Internet all along?
I even completely reset Brave (because I thought maybe it somehow cached my internal IP address) and retried but still I can access app2 over the Internet.

So to me it seems an attacker could access all of my sensitive applications by simply spoofing their IP address to be an internal one!?

How can I effectively prevent this?

The network 192.168.178.0/24 is private and can’t be routed over the Internet.

If the domain DNS is only in you local network, how can you access it via Internet?

What is Traefik access log showing you?

It really is strange.

Both times, I can see the same IP address (my phone's IP address assigned by my ISP) in the access logs.

When accessing via Chrome (403 Forbidden):

109.42.11x.1xx - - [07/Aug/2023:19:03:38 +0000] "GET / HTTP/2.0" 403 9 "-" "-" 78 "jd2@docker" "-" 0ms
109.42.11x.1xx - - [07/Aug/2023:19:03:38 +0000] "GET /favicon.ico HTTP/2.0" 403 9 "-" "-" 79 "jd2@docker" "-" 0ms

When accessing via Brave (200 OK):

109.42.11x.1xx - - [07/Aug/2023:19:03:08 +0000] "GET / HTTP/1.1" 200 10439 "-" "-" 16 "x-jd2@docker" "http://172.19.0.2:5800" 1ms
109.42.11x.1xx - - [07/Aug/2023:19:03:09 +0000] "GET /app/styles/font-awesome.min.css?v=9a02bd6236 HTTP/1.1" 304 0 "-" "-" 17 "x-jd2@docker" "http://172.19.0.2:5800" 0ms
...

I cannot wrap my head around why two different browsers are being treated differently?

This is my static config file:

api:
  dashboard: true
entryPoints:
  http:
    address: ":80"
  https:
    address: ":443"
providers:
  docker:
    endpoint: "unix:///var/run/docker.sock"
    exposedByDefault: false
  file:
    filename: "./dynamic_conf.yml"
certificatesResolvers:
  http:
    acme:
      email: *****@gmail.com
      storage: acme.json
      httpChallenge:
        entryPoint: http
accessLog:
  filePath: "./logs/access.log"

This is my dynamic config file:

tls:
  options:
    default:
      minVersion: VersionTLS12
      cipherSuites:
        - TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
        - TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
        - TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305
        - TLS_AES_128_GCM_SHA256
        - TLS_AES_256_GCM_SHA384
        - TLS_CHACHA20_POLY1305_SHA256
      curvePreferences:
        - CurveP521
        - CurveP384
      sniStrict: true
http:
  middlewares:
    secHeaders:
      headers:
        browserXssFilter: true
        contentTypeNosniff: true
        frameDeny: true
        sslRedirect: true
        #HSTS Configuration
        stsIncludeSubdomains: true
        stsPreload: true
        stsSeconds: 31536000
        customFrameOptionsValue: "SAMEORIGIN"
    httpsRedirect:
      redirectScheme:
        scheme: https
        permanent: true
    localOnly:
      ipWhitelist:
        sourceRange: 192.168.178.0/24

Labels for my app2 service:

    labels:
      - traefik.enable=true
      - traefik.http.routers.x-jd2.rule=Host(`app2.mydomain.com`)
      - traefik.http.routers.x-jd2.entrypoints=http
      - traefik.http.routers.jd2.rule=Host(`app2.mydomain.com`)
      - traefik.http.routers.jd2.entrypoints=https
      - traefik.http.routers.jd2.tls=true
      - traefik.http.routers.jd2.tls.certresolver=http
      - traefik.http.routers.jd2.middlewares=localOnly@file,secHeaders@file,httpsRedirect@file
      - traefik.http.services.jd2.loadbalancer.server.port=5800

mydomain.com can also be publicly resolved to my router's IP address!

Ok I think I found the issue myself...

Apparently the http entrypoint was still working because I didn't assign it with the middleware. I added it now (4th line) and access is being blocked:

    labels:
      - traefik.enable=true
      - traefik.http.routers.x-jd2.rule=Host(`app2.mycomain.com`)
      - traefik.http.routers.x-jd2.entrypoints=http
      - traefik.http.routers.x-jd2.middlewares=localOnly@file,httpsRedirect@file
      - traefik.http.routers.jd2.rule=Host(`app2.mycomain.com`)
      - traefik.http.routers.jd2.entrypoints=https
      - traefik.http.routers.jd2.tls=true
      - traefik.http.routers.jd2.tls.certresolver=http
      - traefik.http.routers.jd2.middlewares=localOnly@file,secHeaders@file
      - traefik.http.services.jd2.loadbalancer.server.port=5800

However, now it is the other way round: When WiFi is enabled I receive 403 Forbidden although I can see my IP address is in the allowed range?

192.168.178.73 - - [07/Aug/2023:19:20:20 +0000] "GET / HTTP/2.0" 403 9 "-" "-" 415 "jd2@docker" "-" 0ms
192.168.178.73 - - [07/Aug/2023:19:20:20 +0000] "GET /favicon.ico HTTP/2.0" 403 9 "-" "-" 416 "jd2@docker" "-" 0ms

EDIT: Solved it finally. Sometimes you have to ask first before you come up with the solution.
Still, thanks a lot @bluepuma77 as your hint with the access log led me to success!

I had to specify a global redirection scheme rather than via middleware:

entryPoints:
  http:
    address: ":80"
    http:
      redirections:
        entryPoint:
          to: https
  https:
    address: ":443"

and adjust the labels the following way:

    labels:
      - traefik.enable=true
      - traefik.http.routers.adguardhome.rule=Host(`ag.mydomain.com`)
      - traefik.http.routers.adguardhome.entrypoints=https
      - traefik.http.routers.adguardhome.tls=true
      - traefik.http.routers.adguardhome.tls.certresolver=http
      - traefik.http.routers.adguardhome.middlewares=localOnly@file,secHeaders@file
      - traefik.http.services.adguardhome.loadbalancer.server.port=8082
      - com.centurylinklabs.watchtower.enable=true

Maybe Brave is using http and therefore no middlewares.

1 Like

This topic was automatically closed 3 days after the last reply. New replies are no longer allowed.