chobits / ngx_http_proxy_connect_module

A forward proxy module for CONNECT request handling
BSD 2-Clause "Simplified" License
1.8k stars 493 forks source link

proxy_connect ignoring location blocks #318

Open markgargan opened 1 month ago

markgargan commented 1 month ago

0. Before Your ASK

  1. Try to find an answer by reading a FAQ.

Ⅰ. Issue Description

I've tried the following configuration as provided in the README.md

server {
    listen                         3128;

    # dns resolver used by forward proxying
    resolver                       8.8.8.8;

    # forward proxy for CONNECT requests
    proxy_connect;
    proxy_connect_allow            443 563;
    proxy_connect_connect_timeout  10s;
    proxy_connect_data_timeout     10s;

    # defined by yourself for non-CONNECT requests
    # Example: reverse proxy for non-CONNECT requests
    location / {
         return 403 "Non-CONNECT requests are forbidden";
    }
}

fully expecting proxy_connect to handle the CONNECT and then the location block to then reject the GET with a 403.

curl --proxy http://localhost:8889 https://kong.mycomp.com:8445

Ⅱ. Describe what happened

The GET request succeeds returning the HTML.

Ⅲ. Describe what you expected to happen

The GET request should return a 403 from the proxy

Ⅳ. How to reproduce it (as minimally and precisely as possible)

I'm building nginx in a docker RHEL8 container using

RUN wget https://nginx.com/download/nginx-1.20.1.tar.gz \ && tar -zxvf nginx-1.20.1.tar.gz \ && cd nginx-1.20.1 \ && git clone https://github.com/openresty/echo-nginx-module.git \ && git clone https://github.com/chobits/ngx_http_proxy_connect_module.git \ && patch -p1 < ngx_http_proxy_connect_module/patch/proxy_connect_rewrite_1018.patch \ && ./configure --add-module=./ngx_http_proxy_connect_module --add-module=./echo-nginx-module \ && make \ && make install

Ⅴ. Anything else we need to know?

  1. If applicable, add nginx debug log.

Ⅵ. Environment:

Nginx with the echo-nginx-module and ngx_http_proxy_connect_module

  1. Tengine/Nginx/OpenResty version (use sbin/nginx -v):
  2. Which patch do you use?
markgargan commented 3 weeks ago

2 weeks since this bug in the readme was highlighted? Any ideas @chobits ?

andarg commented 1 week ago

same issue

chobits commented 1 week ago

When you run this command curl --proxy http://localhost:8889 https://kong.mycomp.com:8445, the curl command will establish a CONNECT tunnel to your localhost 's port 8889, then all the data sent by curl will be handled by proxy_connect module, proxy_connect will not process the internal data flow inside the CONNECT tunnel, it just proxied it to the backend destination kong.mycomp.com:8445. So the localtion / { return 403 .. } will not work for this CONNECT data flow.

So what you observed is as expected.

$ curl --proxy localhost:8889 https://kong.mycomp.com:8445 -sv
*   Trying [::1]:8889...
* connect to ::1 port 8889 failed: Connection refused
*   Trying 127.0.0.1:8889...
* Connected to localhost (127.0.0.1) port 8889
* CONNECT tunnel: HTTP/1.1 negotiated
* allocate connect buffer
* Establish HTTP proxy tunnel to kong.mycomp.com:8445
> CONNECT kong.mycomp.com:8445 HTTP/1.1
> Host: kong.mycomp.com:8445
> User-Agent: curl/8.4.0
> Proxy-Connection: Keep-Alive
>
...
$ nc -l 8889
CONNECT kong.mycomp.com:8445 HTTP/1.1
Host: kong.mycomp.com:8445
User-Agent: curl/8.4.0
Proxy-Connection: Keep-Alive

^------- then proxy_connect will handle this tcp connection and its internal data flow includeing 
CONNECT request and the following SSL requests, so `location / { return 403 ...}` block 
will not work for this scenario.
markgargan commented 1 week ago

Thanks a lot for getting back to us @chobits. I guess what myself and I believe @andarg may be trying as well is to create a form of MITM forwarding proxy. In fiddler there is an autoresponder tab that allows you to intercept calls coming through fiddler and return different responses for application coding testing and chaos testing. So instead of going to the real host it would intercept the call and return say a 400 or a 502 for the gateway being down. Also it can introduce delays which Id hoped to achieve using the echo module in nginx.

It appears the problem you have solved is that up until this point nginx couldn't handle CONNECT requests? The Get and Post sent through a CONNECT tunnel isn't interceptible? Am I right in saying that?

The 'location /' block you've provided that returns the 403 is only for GET POST requests that weren't established with a CONNECT request first. They don't go down the CONNECT tunnel.

Thanks Mark.

chobits commented 6 days ago

It appears the problem you have solved is that up until this point nginx couldn't handle CONNECT requests? The Get and Post sent through a CONNECT tunnel isn't interceptible? Am I right in saying that?

Yes. Because The design of the CONNECT tunnel protocol is overly simple, as the proxy server cannot obtain information beyond the destination address. Therefore, it cannot determine what protocol the data stream is using unless the server makes a guess. Moreover, if it’s SSL traffic, the server cannot decrypt it without the private key of the destination address.

The 'location /' block you've provided that returns the 403 is only for GET POST requests that weren't established with a CONNECT request first. They don't go down the CONNECT tunnel.

Yes. This location / block is reserved for users to define by theirselves to handle the HTTP requests that are not inside the tunnel.