jetty / jetty.project

Eclipse Jetty® - Web Container & Clients - supports HTTP/2, HTTP/1.1, HTTP/1.0, websocket, servlets, and more
https://eclipse.dev/jetty
Other
3.82k stars 1.91k forks source link

Document org.eclipse.jetty.client.Socks4Proxy "secure" parameter #7647

Closed cowwoc closed 5 months ago

cowwoc commented 2 years ago

Target Jetty version(s)

11.0.8

Enhancement Description

Socks4Proxy has a constructor that takes a boolean secure argument. I'd love to understand the implication of true and false values for this parameter. All I know is that when I set secure=true I am no longer able to tunnel through a SOCKS proxy :)

First, I'd like to understand what's insecure about secure=false. Secondly, I'd like to understand why secure=true is failing for me.

What I'm doing:

I used Apache Mina to create a SOCKS proxy over SSH tunnel. I can connect Socks4Proxy(secure=false) to it, but secure=true fails. If I understood the meaning of this parameter then maybe I could circle back to the MINA guys and ask them what it would take to make secure=true work.

joakime commented 2 years ago

This setting is for the initial tunnel established between the client and the socks4 proxy server, before the request is sent.

secure=false is a socks4 proxy server using a scheme of http and no ssl. secure=true is a socks4 proxy server using a scheme of https and mandatory ssl.

If you have a tunnel that's unencrypted between the client and the socks4 proxy server, but a request that's https, then the initial connection between the client and the socks4 proxy server will show the proxy protocol to establish the connection in a non-encrypted way, but the rest of the conversation is encrypted (the client negotiates the TLS connection between itself and the destination server. the socks4 proxy server is just forwarding bytes back and forth)

That help?

joakime commented 2 years ago

The most common setup we encounter is secure=false btw. There's really no point in encrypting twice.

cowwoc commented 2 years ago

@joakime If I understood you correctly, given:

When secure=false the request and response sent between the proxy client and server will be unencrypted but the communication between the proxy and destination servers might be encrypted if the request is HTTPS.

Is that correct?

joakime commented 2 years ago

@cowwoc not sure I understand.

You start with an HttpClient that wants to talk to a destination making a request for a specific resource, using HTTP.

Lets say you have ...

  1. A Socks Proxy on proxy.machine.com port 9999
  2. A Request to https://eclipse.org/jetty/

This now becomes ...

  1. HttpClient connects to socks proxy server at proxy.machine.com at port 9999
  2. HttpClient sends socks4 proxy protocol to tunnel the connection to "eclipse.org" on port "43"
  3. HttpClient receives confirmation of tunneled connection is established
  4. HttpClient initiates TLS handshake with eclipse.org
  5. HttpClient sends HTTP request for resource path "/jetty/" using method "GET"

Not sure how this fits in your scenario.

cowwoc commented 2 years ago

@joakime I think we're on the same page.

My understanding is that if secure=false then the communication between HttpClient and the proxy server will remain unencrypted, regardless of whether the proxied request is HTTP or HTTPS.

Meaning, if I issue an HTTPS request to eclipse.org through proxy.machine.com then:

  1. HttpClient will send an (unencrypted) HTTP request to proxy.machine.com
  2. proxy.machine.com will issue an (encrypted) HTTPS request to eclipse.org based on the request from step 1.
  3. eclipse.org will respond with an encrypted response.
  4. proxy.machine.com will decrypt the response, and forward it to HttpClient as an (unencrypted) HTTP response.

Is that correct?

My understanding is that the proxy acts as a man-in-the-middle. Are you saying otherwise? Will HttpClient somehow communicate with eclipse.org over an encrypted tunnel even if secure=false? Thank you.

joakime commented 2 years ago

Meaning, if I issue an HTTPS request to eclipse.org through proxy.machine.com then:

  1. HttpClient will send an (unencrypted) HTTP request to proxy.machine.com

Incorrect, there's no HTTP request here. It's just the simple SOCKS4 proxy protocol. The only information passed to the proxy.machine.com at this step is ...

  1. A request to "connect" to "eclipse.org" on port 9999 (this the request to tunnel)
  2. authentication details for the proxy.machine.com

This "connect" is just a simple tcp connect from proxy.machine.com to eclipse.org:9999, nothing else, no TLS, no data is sent to eclipse.org:9999. At this point HttpClient is free to pass anything to proxy.machine.com and it will forward those bytes unaltered to eclipse.org:9999 (and vice versa back to HttpClient).
In fact, it doesn't even have to be HTTP/HTTPS, it can be any protocol supported by your SOCKS4. A typical SOCKS4 server supports anything built on top of TCP.

  1. proxy.machine.com will issue an (encrypted) HTTPS request to eclipse.org based on the request from step 1.

Also incorrect, the proxy.machine.com doesn't issue HTTP or HTTPS. That's for the HttpClient to do, and it will only do that once the TLS handshake is complete once the tunnel is established. Making proxy.machine.com only aware of the destination IP and port, but not privy to any other information, definitely not the HTTP request details.

  1. eclipse.org will respond with an encrypted response.

Nope, the entire encrypted conversation is between HttpClient and eclipse.org, proxy.machine.com is not involved there, it's merely passing bytes back and forth. It was never involved in the TLS negotiation or the HTTP exchange.

  1. proxy.machine.com will decrypt the response, and forward it to HttpClient as an (unencrypted) HTTP response.

proxy.machine.com does not encrypt/decrypt between itself and eclipse.org. proxy.machine.com can only encrypt/decrypt between the HttpClient and itself. And only for the purposes of establishing the "connect" (aka tunnel) All traffic in/out of proxy.machine.com and eclipse.org are just raw bytes back and forth, no extra work is performed by proxy.machine.com on those bytes (including encryption).

joakime commented 2 years ago

Here's the basics of SOCKS ...

socks-basics.puml

socks-basics

If we put HTTP into this mix, we get ...

socks-bascis-with-http.puml

socks-basics-with-http

If we encrypt both connections we get this ...

socks-with-tls-both-sides-with-http.puml

socks-with-tls-both-sides

To conclude, the Socks4Proxy "secure" setting is about the connection between the Client and the Socks Proxy, it has no relationship or behavior with any connection to the target server.

You could even have a setup where the connection between the Client and Socks Proxy is encrypted, but the traffic from the Socks Proxy to the Target Server is NOT encrypted. (that's a perfectly valid and common scenario)

cowwoc commented 2 years ago

Thank you.

So if I understand correctly, secure=true protects against man-in-the-middle attacks between the proxy and myself. It prevents third parties from finding out which servers I am connecting to and/or changing which servers I connect to. Is that correct?

I'm still a bit confused about the socks handshake though. In the following scenario, who is the "client", "socks server" and "target server"?

  1. I invoke ssh -N -D 9090 [USER]@[SERVER_IP] where [SERVER IP] is some arbitrary server that I designate as my proxy.
  2. The ssh client logs into the remote server and establishes a SOCKS tunnel back to my machine (bound to localhost:9090).
  3. I open a web browser and configure "localhost:9090" as the address of the SOCKS proxy server.
  4. If I browse https://myexternalip.com/raw the browser displays the proxy's IP address.
  5. If I browse https://websniffer.cc/my I see X-Forwarded-For contains the proxy's IP address.

It sounds as if the machine I am SSHing into plays the role of both the "socks server" and "target server". Any website I hit through the proxy doesn't seem to be aware that some 3rd party is directing the calls behind the proxy. Am I wrong?

github-actions[bot] commented 1 year ago

This issue has been automatically marked as stale because it has been a full year without activity. It will be closed if no further activity occurs. Thank you for your contributions.

github-actions[bot] commented 6 months ago

This issue has been automatically marked as stale because it has been a full year without activity. It will be closed if no further activity occurs. Thank you for your contributions.

sbordet commented 5 months ago

Sorry for the late reply.

So if I understand correctly, secure=true protects against man-in-the-middle attacks between the proxy and myself. It prevents third parties from finding out which servers I am connecting to and/or changing which servers I connect to. Is that correct?

Correct.

If secure=true, the client will encrypt the communication between the client and the proxy. The client will connect to the proxy via TLS and validate the proxy certificate. At this point, no MITM can decrypt that traffic. What happens next is that the client will send to the proxy the information to establish the tunnel, and that information cannot be seen by a MITM.

In the following scenario, who is the "client", "socks server" and "target server"?

"Client" is the browser. "Socks server" is the SOCKS proxy, so in your case SERVER_IP. "Target server" is the server name you put in the browser's address bar (in your case myexternalip.com, etc.).

When you use the browser for myexternalip.com, it will look at its configuration and see it has a proxy. Rather than connecting to myexternalip.com it will connect to the SOCKS proxy instead, and send to the SOCKS proxy a binary packet containing the target server information (host and port) to connect to.

Then the SOCKS proxy will establish a connection to myexternalip.com and create a tunnel between the client and the target server: the client will send bytes to the proxy, the proxy will forward them to the target server, and viceversa.

If you are using https in your browser, the browser will send encrypted bytes into the tunnel.

I'll update the javadocs of the relevant classes.