Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bug: absolute URL prevent the use of a reverse proxy with a different path in front of the stats #294

Open
netchild opened this issue Apr 12, 2024 · 4 comments

Comments

@netchild
Copy link

Hi,

I want to protect access to the vts stats. So at the official URL (let's assume "/vts") nginx proxies to an oauth2 proxy which does the autentication, and then passes the request to "/realvts" on the same nginx (it has access rules to allow only the internal access on the same machine). "/realvts" is configured with the vhost_traffic_status_display.

If I access with a browser /vts, the oauth2 proxy is doing its job, gives me the content of /realvts, but then the browser tries to access /realvts/format/json instead of /vts/format/json. This is because the html source has var vtsStatusURI = "/realvts//format/json", instead of using a relative url (untested: var vtsStatusURI = "./format/json", or maybe var vtsStatusURI = "format/json",).

So:

  • initial access: browser /vts -> nginx /vts -> oauth2 proxy /realvts -> same nginx /realvts -> vts module
  • wrong subsequent request from the status page: browser /realvts -> nginx /realvts -> 403
  • intended subsequent request from the status page: browser /vts -> nginx /vts -> oauth2 proxy /realvts -> same nginx /realvts -> vts module

This doesn't work, as the browser on a remote system is not allowed to access /realvts.

Bye,
Alexander.

@u5surf
Copy link
Collaborator

u5surf commented May 24, 2024

@netchild Hi, sorry for late.

/realvts/format/json instead of /vts/format/json. This is because the html source has var vtsStatusURI = "/realvts//format/json", instead of using a relative url

The below doc says that
vtsStatusURI can be overwritten after the module installed. Thus we can exchange the value of vtsStatusURL to your accessible one, e.g. `vtsStatusURI = “/vts/format/json”

https://github.com/vozlt/nginx-module-vts?tab=readme-ov-file#to-customize-after-the-module-installed

@netchild
Copy link
Author

The FreeBSD port doesn't install the template. I have to dig into the sources and give it a try.

Nevertheless, having a relative path instead of an absolute path would reduce the need to modify it and have it simply work out of the box in more cases.

@u5surf
Copy link
Collaborator

u5surf commented May 25, 2024

@netchild

Nevertheless, having a relative path instead of an absolute path would reduce the need to modify it and have it simply work out of the box in more cases.

Indeed, we tested to exchange vtsStatusURI to the relative path, it seems work fine below.

WebUI:
スクリーンショット 2024-05-25 10 34 15
html source:
スクリーンショット 2024-05-25 10 37 23

nginx.conf

http {
    include mime.types;
    default_type application/octet-stream;

    vhost_traffic_status_zone shared:vhost_traffic_status:32m;
    vhost_traffic_status_zone;
    #vhost_traffic_status_bypass_upstream_stats off;
    proxy_cache_path /var/cache/nginx keys_zone=zone1:1m max_size=1g inactive=24h;

    upstream backend {
        zone backend 64k;
        server localhost:8080;
    }
    server {
        listen 8081;
        location / {
            proxy_cache zone1;
            proxy_pass http://backend;
            access_log /usr/local/nginx/logs/access.log;
        }
    }
    server {
        listen 8082;
        location /status {
            vhost_traffic_status_display;
            vhost_traffic_status_display_format html;
            vhost_traffic_status_bypass_stats on;
        }
        location /format/json {
            vhost_traffic_status_display;
            vhost_traffic_status_display_format json;
            vhost_traffic_status_bypass_stats on;
        }
    }
    server {
        root html;
        listen 8080;
        location / {
            index  index.html index.htm;
        }
    }
}

if it is applicable for your usecase with above configuration is used, it probably should protect the endpoint /format/json and /status or listening port 8082.

But, it is unnecessary /format/json because the conventional config is satisfy without this. It will have been breaking change.

@netchild
Copy link
Author

I don't understand why you have /format/json in the nginx config. The relative path should resolve to /status/./format/json which should resolve to /status/format/json, so this location part should not be needed in the nginx config.

Real world example of what I try:
nginx.conf:

upstream vstatus {
        server localhost:4182;
        keepalive 2;
}

server {
        listen          443 ssl http2 reuseport accept_filter=tlsready;
...
# needed by oauth2 proxy to authenticate
location ~ /voauth2(?<vpath>.*) {
       proxy_redirect off;

       include common.proxy.conf;

       proxy_pass_request_headers on;
       proxy_set_header Connection "keep-alive";
       proxy_store off;
       # internal oauth2 proxy access without TLS for now (testing/debugging)
       proxy_pass http://vstatus/voauth2$vpath$is_args$args;

       gzip on;
       gzip_proxied any;
       gzip_types *;
}

# the path to protect with oauth2 authentication, the real data is at https://server.tld/vstatus which the oauth2 proxy accesses behind the scenes
location ~ /status(?<statpath>.*) {
       proxy_redirect off;

       include common.proxy.conf;

       proxy_pass_request_headers on;
       proxy_set_header Connection "keep-alive";
       proxy_store off;
       # internal oauth2 proxy access without TLS for now (testing/debugging)
       proxy_pass http://vstatus/vstatus$statpath$is_args$args;

       gzip on;
       gzip_proxied any;
       gzip_types *;
}

location /vstatus {
        # https://github.com/vozlt/nginx-module-vts
       allow   127.0.0.1;
       allow   ::1;
       allow <local IPs>;
       deny    all;


        # don't count the status traffic
        vhost_traffic_status_bypass_limit on;
        vhost_traffic_status_bypass_stats on;
        # enable stats display
        vhost_traffic_status_display;
        vhost_traffic_status_display_format html;
}

So the /status goes to the oauth2 proxy, which accesses https://localhost/vstatus after successful auth. The browser only has access to /status, as such it shall retrieve /status/xxx. What the oauth2 proxy fetches is /vstatus/xxx. Any reference inside xxx should ideally be relative, so that the browser generates the URL /status/xyz when he sees "./xyz" or "xyz" instead of "/vstatus/xyz".

While your module only knows about /vstatus, the browser can only access /status. The oauth2 proxy accesses /vstatus, but doesn't rewrite URLs in java script. I can not instruct nginx to rewrite URLs from /vstatus to /status, as the oauth proxy makes the internal request to this URL (which is allowed from localhost). As such the most practical solution is to let the browser construct the real path to access on it's own. A relative path solves this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants