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

authorization for https connections? #42

Closed
legale opened this issue Apr 30, 2018 · 33 comments
Closed

authorization for https connections? #42

legale opened this issue Apr 30, 2018 · 33 comments
Assignees
Labels

Comments

@legale
Copy link

legale commented Apr 30, 2018

Hi. Thank you for your work.

Is there any way to enable authorization for https connections?

@chobits
Copy link
Owner

chobits commented May 7, 2018

hi @legale

could you give more details of how to reproduce this issue?

@chobits chobits changed the title authorization authorization for https connections? Jun 4, 2018
@toadzhou
Copy link

toadzhou commented Sep 28, 2018

Hi @chobits
Auth_basic is invalid for https

curl -x 127.0.0.1:3128 http:https://www.test.com 401
curl -u admin:admin -x 127.0.0.1:3128 http:https://www.test.com 200
curl -x 127.0.0.1:3128 https://www.test.com 200
curl -u admin:admin -x 127.0.0.1:3128 https://www.test.com 200

server {
    listen                         3128;

    # dns resolver used by forward proxying
    resolver                       8.8.8.8;


    # forward proxy for CONNECT request
    proxy_connect;
    proxy_connect_allow            all;
    #proxy_connect_allow            80 443 563;
    proxy_connect_connect_timeout  100s;
    proxy_connect_read_timeout     100s;
    proxy_connect_send_timeout     100s;

    # forward proxy for non-CONNECT request
    location / {
        # auth
        auth_basic "test auth";        #This is invalid for https
        auth_basic_user_file htpasswd;

        autoindex on;
        proxy_pass http:https://$host;
        proxy_set_header Host $host;
    }
}

@gamelton
Copy link

gamelton commented Oct 4, 2018

It seems there is issue with HTTPS basic authentication.

I get 401 Unauthorized.

Here is nginx config

server {
    listen                         3129 ssl;
    ssl_certificate                /etc/letsencrypt/live/proxy.address/fullchain.pem;
    ssl_certificate_key            /etc/letsencrypt/live/proxy.address/privkey.pem;
    resolver                       8.8.8.8;
    auth_pam                       "nginxProxyAuth";
    auth_pam_service_name          "nginx";
    proxy_connect;
    proxy_connect_allow            all;
    location / {
        proxy_pass                 http:https://$host;
        proxy_set_header           Host $host;
    }
}

Here is curl trace

curl --proxy https://proxy.address:3129 http:https://example.com/ --proxy-user user:password --include --verbose --proxy-cacert "C:\curl\bin\curl-ca-bundle.crt"

* Connected to proxy.address (1.2.3.4) port 3129 (#0)
* successfully set certificate verify locations:
*   CAfile: C:\curl\bin\curl-ca-bundle.crt
  CApath: none
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384
* Proxy certificate:
*  subject: CN=proxy.address
*  start date: Sep 27 17:32:01 2018 GMT
*  expire date: Dec 26 17:32:01 2018 GMT
*  subjectAltName: host "proxy.address" matched cert's "proxy.address"
*  issuer: C=US; O=Let's Encrypt; CN=Let's Encrypt Authority X3
*  SSL certificate verify ok.
* Proxy auth using Basic with user 'user'
> GET http:https://example.com/ HTTP/1.1
> Host: example.com
> Proxy-Authorization: Basic cm9vdDpTTHNza29yZA==
> User-Agent: curl/7.61.1
> Accept: */*
> Proxy-Connection: Keep-Alive
>
< HTTP/1.1 401 Unauthorized

I happen to have squid configured on the same machine. HTTPS basic auth works on it.

* Connected to proxy.address (1.2.3.4) port 3129 (#0)
* successfully set certificate verify locations:
*   CAfile: C:\curl\bin\curl-ca-bundle.crt
  CApath: none
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / AES256-GCM-SHA384
* Proxy certificate:
*  subject: CN=proxy.address
*  start date: Sep 27 17:32:01 2018 GMT
*  expire date: Dec 26 17:32:01 2018 GMT
*  subjectAltName: host "proxy.address" matched cert's "proxy.address"
*  issuer: C=US; O=Let's Encrypt; CN=Let's Encrypt Authority X3
*  SSL certificate verify ok.
* Proxy auth using Basic with user 'root'
> GET http:https://example.com/ HTTP/1.1
> Host: example.com
> Proxy-Authorization: Basic cm9vdDpTTHNza29yZA==
> User-Agent: curl/7.61.1
> Accept: */*
> Proxy-Connection: Keep-Alive
>
< HTTP/1.1 200 OK

@gamelton
Copy link

gamelton commented Oct 4, 2018

Actually it seems nginx PAM authentication breaks when used with this module.
HTTP basic authentication also fails.

curl --proxy http:https://proxy.address:3128 http:https://example.com/ --proxy-user user:password --include --verbose

* Connected to proxy.address (1.2.3.4) port 3128 (#0)
* Proxy auth using Basic with user 'user'
> GET http:https://example.com/ HTTP/1.1
> Host: example.com
> Proxy-Authorization: Basic cm9vdDpTTHNza29yZA==
> User-Agent: curl/7.61.1
> Accept: */*
> Proxy-Connection: Keep-Alive
>
< HTTP/1.1 401 Unauthorized

nginx configuration

server {
    listen                         3128;
    resolver                       8.8.8.8;
    auth_pam                       "nginxProxyAuth";
    auth_pam_service_name          "nginx";
    proxy_connect;
    proxy_connect_allow            all;
    location / {
        proxy_pass                 http:https://$host;
        proxy_set_header           Host $host;
    }
}

I used nginx PAM auth module. I checked that basic auth on simple page works. Please @chobits advise on authentication options for this module.

@chobits
Copy link
Owner

chobits commented Dec 3, 2018

hi,

let me check.

(I only check nginx basic auth module before)

@toadzhou
Copy link

toadzhou commented Dec 4, 2018

nginx的auth模块也不起作用吧

@moralrebuild
Copy link

moralrebuild commented Jun 17, 2019

any progress about this critical bug? From my point of view, it provides little value if this module insists to break/deny the existing authentication mechanism.

@chobits
Copy link
Owner

chobits commented Jun 17, 2019

any progress about this critical bug? From my point of view, it provides little value if this module insists to break/deny the existing authentication mechanism.

This module can work with lua-nginx-module. During REWRITE phase (directive rewrite_by_lua_*), you can check request and detect whether to break/deny the request.

But you should know that the request which you can check is only the CONNECT request, not any data proxied under CONNECT tunnel.

@moralrebuild
Copy link

moralrebuild commented Jun 17, 2019

@chobits Thanks for your quick reply. But we all want is nothing else but basic auth to prevent illegal traffic pass through forward proxy. Do you think it is not important?

@chobits
Copy link
Owner

chobits commented Jun 17, 2019

hi @moralrebuild

@gamelton 's case has two problem, which are not associated with proxy connect module.
(#42 (comment))

  1. His test case does not generate CONNECT request, please note that proxy connect module can only handle CONNECT request, other requests (GET/POST) is handled by nginx itself.
  2. The auth module of his test case is not nginx auth basic module, it's nginx PAM auth module. Why this module cannot work, should be debugged with https://github.com/sto/ngx_http_auth_pam_module. Although, it does not concern proxy_connect module, because it works for GET request.

Note that I have checked proxy_connect module can work under auth basic module (Note that my test case worked for CONNECT request with auth basic header, NOT for GET request).

@chobits
Copy link
Owner

chobits commented Jun 17, 2019

Note that requests under CONNECT tunnel, such as some GET/POST requests cannot be checked by auth basic module for your proxy_connect nginx.

This module only handles CONNECT request, the raw stream (maybe GET/POST request, or anyother data stream) under CONNECT tunnel cannot be parsed and is passed to backend server directly.

(The similar problem for this case, see #108 (comment). )

@deba12
Copy link

deba12 commented Jun 17, 2019

I think this module should supports
proxy authentication
https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/407

@moralrebuild
Copy link

moralrebuild commented Jun 17, 2019

@chobits
Let me explain what I observed.

  1. I build this module from its master branch with Nginx 1.16.0.
  2. the nginx configuration
server {
	    listen 443 ssl;
	    listen [::]:443 ssl;
	    server_name my.domain;
	    auth_basic "server auth";
	    auth_basic_user_file /etc/nginx/htpasswd;
	    ssl_certificate /etc/letsencrypt/live/my.domain/fullchain.pem;
	    ssl_certificate_key /etc/letsencrypt/live/my.domain/privkey.pem;
	    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
	    ssl_session_timeout 5m;
	    ssl_protocols TLSv1.3 TLSv1.2 TLSv1.1;
	    ssl_prefer_server_ciphers on;
	    ssl_session_cache builtin:1000 shared:SSL:10m;
	    access_log on;
	    root         /var/www/html;
	    index index.html index.htm index.nginx-debian.html;

	    # dns resolver used by forward proxying
	    resolver                       8.8.8.8;

	    # forward proxy for CONNECT request
	    proxy_connect;
	    proxy_connect_allow            443 22;
	    proxy_connect_connect_timeout  10s;
	    proxy_connect_read_timeout     10s;
	    proxy_connect_send_timeout     10s;
	    
	    # forward proxy for non-CONNECT request
	    location / {
	        proxy_pass http:https://$host;
	        proxy_set_header Host $host;
	    }
	}
  1. the test results for two use cases: one is forward proxying, another is tunnelling ssh traffic over https
    3.1 curl
curl https://github.com/ -v -x my.domain:443 --proxy-user user01:password01
*   Trying 111.222.33.44...
* TCP_NODELAY set
* Connected to (nil) (111.222.33.44) port 443 (#0)
* Establish HTTP proxy tunnel to github.com:443
* Proxy auth using Basic with user 'user01'
> CONNECT github.com:443 HTTP/1.1
> Host: github.com:443
> Proxy-Authorization: Basic cHVuZ2lzemI6TEdtMzZCaXc5SlkwdTGFqNA==
> User-Agent: curl/7.52.1
> Proxy-Connection: Keep-Alive
>
< HTTP/1.1 400 Bad Request
< Server: nginx/1.16.0
< Date: Mon, 17 Jun 2019 07:44:24 GMT
< Content-Type: text/html
< Content-Length: 255
< Connection: close
<
* Received HTTP code 400 from proxy after CONNECT
* Curl_http_done: called premature == 0
* Closing connection 0

3.2 proxytunnel

proxytunnel -v -E -p my.domain:443 -P pungiszb:LGm36Biw9JY1Laj4 -d my.domain:22     # for testing only purpose, enable one proxy rather than two
SSL client to proxy enabled
Local proxy my.domain resolves to 111.222.33.44
Connected to my.domain:443 (local proxy)
Set SNI hostname to my.domain

Tunneling to my.domain:22 (destination)
Communication with local proxy:
 -> CONNECT my.domain:22 HTTP/1.1
 -> Host: my.domain:9443
 -> Proxy-Authorization: Basic cHVuZ2lzemI6TEdtMzZCaXc5SlkwdTGFqNA==
 -> Proxy-Connection: Keep-Alive
 <- HTTP/1.1 401 Unauthorized
HTTP return code: 401 Unauthorized
 <- Server: nginx/1.16.0
 <- Date: Mon, 17 Jun 2019 07:53:17 GMT
 <- Content-Type: text/html
 <- Content-Length: 179
 <- Connection: keep-alive
 <- WWW-Authenticate: Basic realm="server auth"

nginx debug log :

2019/06/17 15:58:29 [debug] 30468#30468: *50954 accept: 10.79.76.14:60038 fd:13
2019/06/17 15:58:29 [debug] 30468#30468: *50954 event timer add: 13: 60000:354427063
2019/06/17 15:58:29 [debug] 30468#30468: *50954 reusable connection: 1
2019/06/17 15:58:29 [debug] 30468#30468: *50954 epoll add event: fd:13 op:1 ev:80002001
2019/06/17 15:58:29 [debug] 30468#30468: *50954 http check ssl handshake
2019/06/17 15:58:29 [debug] 30468#30468: *50954 http recv(): 1
2019/06/17 15:58:29 [debug] 30468#30468: *50954 https ssl handshake: 0x16
2019/06/17 15:58:29 [debug] 30468#30468: *50954 tcp_nodelay
2019/06/17 15:58:29 [debug] 30468#30468: *50954 SSL server name: "my.domain"
2019/06/17 15:58:29 [debug] 30468#30468: *50954 SSL_do_handshake: -1
2019/06/17 15:58:29 [debug] 30468#30468: *50954 SSL_get_error: 2
2019/06/17 15:58:29 [debug] 30468#30468: *50954 reusable connection: 0
2019/06/17 15:58:29 [debug] 30468#30468: *50954 SSL handshake handler: 0
2019/06/17 15:58:29 [debug] 30468#30468: *50954 SSL_do_handshake: 1
2019/06/17 15:58:29 [debug] 30468#30468: *50954 SSL: TLSv1.2, cipher: "ECDHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH Au=RSA Enc=AESGCM(256) Mac=AEAD"
2019/06/17 15:58:29 [debug] 30468#30468: *50954 reusable connection: 1
2019/06/17 15:58:29 [debug] 30468#30468: *50954 http wait request handler
2019/06/17 15:58:29 [debug] 30468#30468: *50954 malloc: 000055DA697591D0:1024
2019/06/17 15:58:29 [debug] 30468#30468: *50954 SSL_read: -1
2019/06/17 15:58:29 [debug] 30468#30468: *50954 SSL_get_error: 2
2019/06/17 15:58:29 [debug] 30468#30468: *50954 free: 000055DA697591D0
2019/06/17 15:58:29 [debug] 30468#30468: *50954 http wait request handler
2019/06/17 15:58:29 [debug] 30468#30468: *50954 malloc: 000055DA697591D0:1024
2019/06/17 15:58:29 [debug] 30468#30468: *50954 SSL_read: 162
2019/06/17 15:58:29 [debug] 30468#30468: *50954 SSL_read: -1
2019/06/17 15:58:29 [debug] 30468#30468: *50954 SSL_get_error: 2
2019/06/17 15:58:29 [debug] 30468#30468: *50954 reusable connection: 0
2019/06/17 15:58:29 [debug] 30468#30468: *50954 posix_memalign: 000055DA6973B4B0:4096 @16
2019/06/17 15:58:29 [debug] 30468#30468: *50954 http process request line
2019/06/17 15:58:29 [debug] 30468#30468: *50954 http request line: "CONNECT my.domain:22 HTTP/1.1"
2019/06/17 15:58:29 [debug] 30468#30468: *50954 http uri: ""
2019/06/17 15:58:29 [debug] 30468#30468: *50954 http args: ""
2019/06/17 15:58:29 [debug] 30468#30468: *50954 http exten: ""
2019/06/17 15:58:29 [debug] 30468#30468: *50954 posix_memalign: 000055DA6970C250:4096 @16
2019/06/17 15:58:29 [debug] 30468#30468: *50954 http process request header line
2019/06/17 15:58:29 [debug] 30468#30468: *50954 http header: "Host: my.domain:22"
2019/06/17 15:58:29 [debug] 30468#30468: *50954 http header: "Proxy-Authorization: Basic  cHVuZ2lzemI6TEdtMzZCaXc5SlkwdTGFqNA=="
2019/06/17 15:58:29 [debug] 30468#30468: *50954 http header: "Proxy-Connection: Keep-Alive"
2019/06/17 15:58:29 [debug] 30468#30468: *50954 http header done
2019/06/17 15:58:29 [debug] 30468#30468: *50954 event timer del: 13: 354427063
2019/06/17 15:58:29 [debug] 30468#30468: *50954 generic phase: 0
2019/06/17 15:58:29 [debug] 30468#30468: *50954 generic phase: 1
2019/06/17 15:58:29 [debug] 30468#30468: *50954 rewrite phase: 2
2019/06/17 15:58:29 [debug] 30468#30468: *50954 rewrite phase: 4
2019/06/17 15:58:29 [debug] 30468#30468: *50954 post rewrite phase: 5
2019/06/17 15:58:29 [debug] 30468#30468: *50954 generic phase: 6
2019/06/17 15:58:29 [debug] 30468#30468: *50954 generic phase: 7
2019/06/17 15:58:29 [debug] 30468#30468: *50954 generic phase: 8
2019/06/17 15:58:29 [debug] 30468#30468: *50954 generic phase: 9
2019/06/17 15:58:29 [debug] 30468#30468: *50954 access phase: 10
2019/06/17 15:58:29 [debug] 30468#30468: *50954 access phase: 11
2019/06/17 15:58:29 [info] 30468#30468: *50954 no user/password was provided for basic authentication, client: 10.79.76.14, server: my.domain, request: "CONNECT my.domain:22 HTTP/1.1", host: "my.domain:22"
2019/06/17 15:58:29 [debug] 30468#30468: *50954 http finalize request: 401, "?" a:1, c:1
2019/06/17 15:58:29 [debug] 30468#30468: *50954 http special response: 401, "?"
2019/06/17 15:58:29 [debug] 30468#30468: *50954 http set discard body
2019/06/17 15:58:29 [debug] 30468#30468: *50954 HTTP/1.1 401 Unauthorized
Server: nginx/1.16.0
Date: Mon, 17 Jun 2019 07:58:29 GMT
Content-Type: text/html
Content-Length: 179
Connection: keep-alive
WWW-Authenticate: Basic realm="server auth"

@chobits
Copy link
Owner

chobits commented Jun 18, 2019

hi @moralrebuild

3.1 curl

For "3.1 curl" case, your nginx server config listens 443 with ssl protocol, while curl command (curl https://... -x ...) creates plain CONNECT request. So nginx server refuses this CONNECT request with 400. Note that curl command cannot create tunnel under SSL protocol. You should disable ssl protocol for listening config.

3.2 proxytunnel

For this case, proxytunnel creates tunnel under SSL protocol, in which case CONNECT request and later proxied stream is under ssl protocol.

But nginx auth_basic module can only handle Authorization header, proxytunnel request header Proxy-Authorization: Basic cHVuZ2lzemI6TEdtMzZCaXc5SlkwdTGFqNA== cannot be checked. Try the following directive to bypass header limit:

        proxy_connect ...;
        ...;

        # set Authorization header via Proxy-Authorization header
        rewrite_by_lua '
            ngx.req.set_header("Authorization", ngx.var.http_proxy_Authorization)
        ';

@chobits
Copy link
Owner

chobits commented Jun 18, 2019

How to do access control using nginx auth basic module

Note that this auth-basic checking only works for CONNECT request, not for proxied requests on the CONNECT tunnel.

  1. nginx config
  • enables proxy_connect module
  • enables auth basic module
  • ❗ transfer Proxy-Authorization header to Authorization header for CONNECT request via rewrite_by_lua directive (because auth basic module can only handle Authorization header)
$ cat conf/nginx.conf

    server {
        listen 8080;

        auth_basic "server auth";
        auth_basic_user_file /Users/xiaochen/work/github/tengine/output/conf/pwd;

        resolver                       8.8.8.8;

        # forward proxy for CONNECT request
        proxy_connect;
        proxy_connect_allow            all;

        # transfer Proxy-Authorization header to Authorization header
        rewrite_by_lua_file /Users/xiaochen/work/github/tengine/output/conf/proxy_auth.lua;

        # forward proxy for non-CONNECT request
        location / {
            proxy_pass http:https://$host;
            proxy_set_header Host $host;

            # If backend wont check Auth header, we should not pass the user/password.
            proxy_hide_header Authorization;
            proxy_hide_header Proxy-Authorization;
        }
    }
$ cat /Users/xiaochen/work/github/tengine/output/conf/proxy_auth.lua

-- check Proxy-Authorization for https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/407
if not ngx.var.http_proxy_authorization then
    ngx.header["Proxy-Authenticate"] = "Basic realm=\"Access to internal site\""
    ngx.exit(407)
end

-- transfer Proxy-Authorization header to Authorization for auth basic module
ngx.req.set_header("Authorization", ngx.var.http_proxy_authorization)
  1. create user/password hello:world for auth_basic_user_file /Users/xiaochen/work/github/tengine/output/conf/pwd
$ htpasswd -c ./conf/pwd hello 
New password:           <<<<<< input "world"
Re-type new password:     <<<<<<< input "world"
Adding password for user hello

$ cat conf/pwd
hello:$apr1$X2Xvv/bM$K17b2lTxih1JlTvyzFyWh1
  1. my curl command:
  • auth passed
$ curl https://github.com -x localhost:8080  --proxy-user hello:world -sv -o /dev/null
HTTP/1.1 200 Connection Established
Proxy-agent: nginx

HTTP/1.1 200 OK
Date: Tue, 18 Jun 2019 07:34:05 GMT
Content-Type: text/html; charset=utf-8
Server: GitHub.com
Status: 200 OK
Vary: X-PJAX
...
  • auth failed without Proxy-Authorization header
$ curl https://github.com -x localhost:8080 -sv -o /dev/null
*   Trying ::1...
* TCP_NODELAY set
* Connection failed
* connect to ::1 port 8080 failed: Connection refused
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 8080 (#0)
* allocate connect buffer!
* Establish HTTP proxy tunnel to github.com:443
> CONNECT github.com:443 HTTP/1.1
> Host: github.com:443
> User-Agent: curl/7.62.0
> Proxy-Connection: Keep-Alive
>
< HTTP/1.1 407
< Server: Tengine/2.3.0
< Date: Tue, 18 Jun 2019 08:03:59 GMT
< Content-Length: 0
< Connection: keep-alive
< Proxy-Authenticate: Basic realm="Access to internal site"
<
* Received HTTP code 407 from proxy after CONNECT
* CONNECT phase completed!
* Closing connection 0

See Also

@chobits
Copy link
Owner

chobits commented Jun 18, 2019

hi @gamelton and @toadzhou

See my comment: #42 (comment).

We should transfer Proxy-Authorization header to Authorization header for auth basic module!!

Thanks for your report~!

@deba12
Copy link

deba12 commented Jun 18, 2019

I think there are two cases interleaved here.

  1. Client have to authenticate it self to nginx-proxy
  2. nginx-proxy have to authenticate it self with upstream proxy

For the first case its fairly simple, just return 407 Proxy Authentication Required (if client does not provide credentials)
Next request client should provide its credentials which can be checked against standard password file.

For second case, we can use proxy_pass_header with client credentials or use proxy_set_header with hard coded credentials

@chobits
Copy link
Owner

chobits commented Jun 18, 2019

hi @deba12

  1. Client have to authenticate it self to nginx-proxy

I have given a tricky way to support Proxy-Authorization via lua-nginx-module(rewrite_by_lua directive) and auth basic module.

See my comment of the test case: #42 (comment).

  1. nginx-proxy have to authenticate it self with upstream proxy

We cannot support this featue, because proxy_connect module wont parse and modify proxied data stream. For why, see #108 (comment).

@chobits chobits self-assigned this Jun 18, 2019
@deba12
Copy link

deba12 commented Jun 18, 2019

I have given a tricky way to support Proxy-Authorization via lua-nginx-module(rewrite_by_lua directive) and auth basic module.

See my comment of the test case: #42 (comment).

yep it should works. But your example have to include at least proxy_hide_header to hide authorization headers ;)

@chobits
Copy link
Owner

chobits commented Jun 18, 2019

hi @deba12

It's unnecessary for CONNECT tunnel, because CONNECT request is only handled by proxy_connect module, there is no header passed to backend for CONNECT request. And later request under CONNECT tunnel is proxied to backend without any modified.

step: CONNECT request handled(no request passed to backend) -> create tcp connection with backned -> pass later request to backend( passthrough without modification)

I mean proxy_hide_header ( any directive of proxy module) wont work for CONNECT request and requests/data stream under CONNECT tunnel.


However, proxy_hide_header can work for plain http proxying, for example curl http:https://xxx -x ip:port via proxy_pass ( its http:https://xxx not https://). This case is handles with following configuration

        # forward proxy for non-CONNECT request
        location / {
            proxy_pass http:https://$host;
            proxy_set_header Host $host;

            # If backend wont check Auth header, we should not pass the user/password.
            proxy_hide_header Authorization;
            proxy_hide_header Proxy-Authorization;
        }

@deba12
Copy link

deba12 commented Jun 18, 2019

@chobits yes, but for plain http connections we have to hide it anyway so why not to include it.
You know most people will just brainlessly copy paste this example. Their credentials will leak to upsteram

@chobits
Copy link
Owner

chobits commented Jun 18, 2019

@chobits yes, but for plain http connections we have to hide it anyway so why not to include it.
You know most people will just brainlessly copy paste this example. Their credentials will leak to upsteram

Yes, I agree. Have updated #42 (comment).

     # If backend wont check Auth header, we should not pass the user/password.
       proxy_hide_header Authorization;
       proxy_hide_header Proxy-Authorization;

@gamelton
Copy link

Hi, @chobits.
Thank you for the reply. I'm looking at your config.

    server {
        listen 8080;

Does it mean that credentials are sent in clear text?
Is it possible to encrypt connection before sending authentication data?
I'm bit confused. What I'm trying to achieve is fully encrypted connection to proxy.

@chobits
Copy link
Owner

chobits commented Jun 19, 2019

hi @gamelton

Hi, @chobits.
Thank you for the reply. I'm looking at your config.

    server {
        listen 8080;

Does it mean that credentials are sent in clear text?
Is it possible to encrypt connection before sending authentication data?
I'm bit confused. What I'm trying to achieve is fully encrypted connection to proxy.

Yes you can config nginx with SSL protocol( listen <port> ssl). For example, you can refer config of #42 (comment).

And you can test it with proxytunnel command from 3.2 proxytunnel test case of #42 (comment). Note that his case is forbidden by 401, you should modify his config with lua-transfer-Proxy-Auth-header lua from my comment #42 (comment) to let auth basic module work well.

@xlcn
Copy link

xlcn commented Dec 12, 2019

How to do access control using nginx auth basic module

Note that this auth-basic checking only works for CONNECT request, not for proxied requests on the CONNECT tunnel.

  1. nginx config
  • enables proxy_connect module
  • enables auth basic module
  • exclamation transfer Proxy-Authorization header to Authorization header for CONNECT request via rewrite_by_lua directive (because auth basic module can only handle Authorization header)
$ cat conf/nginx.conf

    server {
        listen 8080;

        auth_basic "server auth";
        auth_basic_user_file /Users/xiaochen/work/github/tengine/output/conf/pwd;

        resolver                       8.8.8.8;

        # forward proxy for CONNECT request
        proxy_connect;
        proxy_connect_allow            all;

        # transfer Proxy-Authorization header to Authorization header
        rewrite_by_lua_file /Users/xiaochen/work/github/tengine/output/conf/proxy_auth.lua;

        # forward proxy for non-CONNECT request
        location / {
            proxy_pass http:https://$host;
            proxy_set_header Host $host;

            # If backend wont check Auth header, we should not pass the user/password.
            proxy_hide_header Authorization;
            proxy_hide_header Proxy-Authorization;
        }
    }
$ cat /Users/xiaochen/work/github/tengine/output/conf/proxy_auth.lua

-- check Proxy-Authorization for https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/407
if not ngx.var.http_proxy_authorization then
    ngx.header["Proxy-Authenticate"] = "Basic realm=\"Access to internal site\""
    ngx.exit(407)
end

-- transfer Proxy-Authorization header to Authorization for auth basic module
ngx.req.set_header("Authorization", ngx.var.http_proxy_authorization)
  1. create user/password hello:world for auth_basic_user_file /Users/xiaochen/work/github/tengine/output/conf/pwd
$ htpasswd -c ./conf/pwd hello 
New password:           <<<<<< input "world"
Re-type new password:     <<<<<<< input "world"
Adding password for user hello

$ cat conf/pwd
hello:$apr1$X2Xvv/bM$K17b2lTxih1JlTvyzFyWh1
  1. my curl command:
  • auth passed
$ curl https://github.com -x localhost:8080  --proxy-user hello:world -sv -o /dev/null
HTTP/1.1 200 Connection Established
Proxy-agent: nginx

HTTP/1.1 200 OK
Date: Tue, 18 Jun 2019 07:34:05 GMT
Content-Type: text/html; charset=utf-8
Server: GitHub.com
Status: 200 OK
Vary: X-PJAX
...
  • auth failed without Proxy-Authorization header
$ curl https://github.com -x localhost:8080 -sv -o /dev/null
*   Trying ::1...
* TCP_NODELAY set
* Connection failed
* connect to ::1 port 8080 failed: Connection refused
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 8080 (#0)
* allocate connect buffer!
* Establish HTTP proxy tunnel to github.com:443
> CONNECT github.com:443 HTTP/1.1
> Host: github.com:443
> User-Agent: curl/7.62.0
> Proxy-Connection: Keep-Alive
>
< HTTP/1.1 407
< Server: Tengine/2.3.0
< Date: Tue, 18 Jun 2019 08:03:59 GMT
< Content-Length: 0
< Connection: keep-alive
< Proxy-Authenticate: Basic realm="Access to internal site"
<
* Received HTTP code 407 from proxy after CONNECT
* CONNECT phase completed!
* Closing connection 0

See Also

hi, i donnot know why, but proxy_hide_header is not work here.. your code work?

@intika
Copy link

intika commented Jan 14, 2020

Not an easy task here while remaining widely compatible and without using MITM ssl... (plus the current solution is not compatible with chrome and others...)

looking forward to what will be implemented against this issue.

@chobits
Copy link
Owner

chobits commented Jan 17, 2020

hi @xlcn

from ur #42 (comment)

hi, i donnot know why, but proxy_hide_header is not work here.. your code work?

Yes, it works, see the example in my comment:

$ curl https://github.com -x localhost:8080  --proxy-user hello:world -sv -o /dev/null
HTTP/1.1 200 Connection Established
Proxy-agent: nginx
^------------------ (1)

HTTP/1.1 200 OK
Date: Tue, 18 Jun 2019 07:34:05 GMT
Content-Type: text/html; charset=utf-8
Server: GitHub.com
Status: 200 OK
Vary: X-PJAX
^------------------- (2)
  • (1) proxy_hide_header can only work for headers of CONNECT-tunnel-create-and-authcheck phase.
  • (2) proxy_hide_header cannot work for these headers, see this faq for details. Maybe ur question is why (2)'s headers cannot be hidden by proxy_hide_header.

@DaniloOliveira28
Copy link

DaniloOliveira28 commented Dec 16, 2020

@chobits do you have a suggestio to use #42 comment without using lua module/script?

Is it possible to rewrite and simplify the line below?

ngx.req.set_header("Authorization", ngx.var.http_proxy_authorization)

@koalabearguo
Copy link


ok,nice work;
I have made a change,when directly access the site(not use as a proxy),use 401 WWW-Authenticate
when use as a proxy for CONNECT METHOD,use 407 Proxy-Authenticate

-- check Proxy-Authorization for https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/407
local http_method = ngx.var.request_method
if not ngx.var.http_proxy_authorization and http_method == "CONNECT" then
        ngx.header["Proxy-Authenticate"] = "Basic realm=\"Access to internal site\""
        ngx.exit(407)
end

-- transfer Proxy-Authorization header to Authorization for auth basic module
if http_method == "CONNECT" then
        ngx.req.set_header("Authorization", ngx.var.http_proxy_authorization)
end

@IanVaughan
Copy link

Do you recommend using OpenResty to get lua-nginx-module and compiling that with ngx_http_proxy_connect_module?
Or the other way round?
As I have Nginx built with this module, but am having issues following install instructions https://github.com/openresty/lua-nginx-module/#installation

@chobits
Copy link
Owner

chobits commented Jul 3, 2021

Do you recommend using OpenResty to get lua-nginx-module and compiling that with ngx_http_proxy_connect_module?
Or the other way round?
As I have Nginx built with this module, but am having issues following install instructions https://github.com/openresty/lua-nginx-module/#installation

If you just use a few functions of nginx OR personal use, there is no difference between using nginx and openresty.

But if you need to use a large number of nginx three-party modules to complete online business, and do not want to maintain the update of each module independently, it is highly recommended that you use nginx bundle (maybe openresty, NGINX Plus, Tengine ...)

@chobits
Copy link
Owner

chobits commented Jul 3, 2021

hi @DaniloOliveira28

@chobits do you have a suggestio to use #42 comment without using lua module/script?

Is it possible to rewrite and simplify the line below?

ngx.req.set_header("Authorization", ngx.var.http_proxy_authorization)

Reply late, this thread is too long.

There is no module that can directly modify and handle the request before the nginx proxy module. Maybe nginx-native module: Perl module can do this also, I rarely use it, only use it to write nginx test case. Lua module is a convenient way to do programming for HTTP request.

For perl module: http:https://nginx.org/en/docs/http/ngx_http_perl_module.html

@chobits
Copy link
Owner

chobits commented Jul 5, 2021

This issue was resolved in #42 (comment).

I Closed and locked this issue. If you have any question, please open a new issue.

@chobits chobits closed this as completed Jul 5, 2021
Repository owner locked as too heated and limited conversation to collaborators Jul 5, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests