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

Add support for HTTPS over HTTP on Node.js #5037

Closed
wants to merge 3 commits into from

Conversation

ppati000
Copy link
Contributor

@ppati000 ppati000 commented Oct 6, 2022

So far, Axios did not support HTTPS requests over HTTP proxies.

This pull request implements of CONNECT requests to establish a tunnel through the proxy. The implementation works with both Connection: close and Connection: keep-alive, so that multiple HTTPS requests can be sent after one CONNECT. Only Node.js is supported for now.

This pull request should fix the following issues, which still seem to be unresolved:

Feedback is highly appreciated!

Caveats

If the upstream server closes the connection first (e.g., when keep-alive is disabled), the proxy may send an RST packet to the client. Here's what I believe is happening after some Wireshark debugging:

  1. After sending the response, the upstream server sends TLS close_notify and FIN=1.
  2. Proxy relays the packet to the client.
  3. Proxy sends FIN reply to upstream server on its own (closing its connection with the upstream server)
  4. Client sends TLS close_notify packet back to the proxy
  5. Proxy does not understand TLS and has already closed the connection to the upstream server => sends RST to client.
  6. Node.js triggers ECONNRESET although the HTTPS response has already been received (res.complete === true).

My mitigation for this issue was to ignore ECONNRESET errors if res.complete === true. This mitigation does not work with follow-redirects, so redirect support is disabled for HTTPS over HTTP.

@@ -47,6 +48,56 @@ function dispatchBeforeRedirect(options) {
}
}

/**
* Provides an HTTP tunnel socket via an HTTP CONNECT request.
* The tunnel socket is used for sending HTTPS requests via an HTTP proxy.
Copy link

@Nevon Nevon Oct 10, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

HTTP requests can be made via an HTTP proxy using the CONNECT method as well. Shouldn't this only create the TlsSocket in case the destination is using HTTPS, and otherwise return the original socket that was used to make the CONNECT request?

EDIT: Oh I see further down that this is only used when the target is HTTPS. So for an HTTP proxy with a target that's not using TLS, it assumes it's not gonna use the connect method, which is quite reasonable for an HTTP client.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Nevon exactly, CONNECT is only used if the destination uses TLS. I figured it would not make that much sense for non-TLS destinations because of the extra round trip.

@ppati000
Copy link
Contributor Author

Will probably get back to this PR after #5097, which will cause some conflicts.

@mikaelfs
Copy link

Any plan or target release version to merge this upstream @ppati000 ? We also happen to stumble on the same https-over-http-proxy issue. It would be great to have this fix in the official release.

@ferranmuntada
Copy link

We have encountered this problem in our project, do you know when it will be added? As soon as possible please!

@jasonsaayman
Copy link
Member

@ppati000 please can you let me know if you will be able to complete this PR? The other PR you mentioned has been merged.

proxy.listen(4000, async () => {
try {
const httpsAgent = new https.Agent({
rejectUnauthorized: false,

Check failure

Code scanning / CodeQL

Disabling certificate validation

Disabling certificate validation is strongly discouraged.
@ppati000
Copy link
Contributor Author

@mikaelfs @ferranmuntada @jasonsaayman Hey everyone, thanks for your interest :) Will look into this pull request again over the holidays.

@foreverest
Copy link

@ppati000 could you share latest news on this please? Really interested in having this asap.

@adriencarbonaro
Copy link

+1

@dudizi
Copy link

dudizi commented Jan 25, 2023

Great job on the PR, @ppati000. It appears that this issue is widely spread, as many 3rd party SDKs use axios. Is there a target release version for a fix so it's just a matter of updating the version dependency?

}

options._httpsOverHttp = proxy.protocol === "http:" && options.protocol === "https:";
Copy link
Contributor

@mbargiel mbargiel Jan 31, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about https over https? You still need a tunnel in that case because you need end-to-end encryption with the intended recipient.

Just for reference, here's how I fixed HTTP CONNECT support for secure HTTPS proxying. My solution relies on the underlying agents (I mentioned it here but I found it a bit too hacky and it required introducing an unmaintained dependency, which I wasn't comfortable with).

You could also check out my fork directly for ideas : mbargiel/axios@e6f9026...feature/fix-proxy/http-connect

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The nice thing with agents is that you don't have to worry about problems with follow-redirects: the tunnel is established in a lower abstraction layer, and once Axios has the socket, it's established properly to the end server. Redirects work over the tunnel.

@mikaelfs
Copy link

mikaelfs commented Feb 1, 2023

@mbargiel The nice thing with agents is that you don't have to worry about problems with follow-redirects: the tunnel is established in a lower abstraction layer, and once Axios has the socket, it's established properly to the end server. Redirects work over the tunnel.

This is actually how we resolved the proxy issue. With custom http/https agent, https-over-http proxy or https-over-https proxy is properly handled by the agent and is independent of proxy handling by axios. If time permits, I will share some write-up explaining our method.

@mbargiel
Copy link
Contributor

mbargiel commented Feb 1, 2023

@mikaelfs This is actually how we resolved the proxy issue. With custom http/https agent, https-over-http proxy or https-over-https proxy is properly handled by the agent and is independent of proxy handling by axios. If time permits, I will share some write-up explaining our method.

Did you use any other library for that? Our own solution was to use https-proxy-agent, but it's a somewhat overly complicated and unmaintained package that isn't self-contained (so, more dependencies...). We were considering keeping the exact same pattern but changing the agent class to hpagent.

I was just hoping to have time to actually open an Axios PR.

@frzsombor
Copy link

frzsombor commented Apr 23, 2023

I'm really not the "is there any update?" comment guy, but this looks like the one last problem with proxies in axios, so would be awesome to get this merged if everything seems ready. Sooo.. is there any update on this? :)

@Thore1954
Copy link

This PR seems dead. I created #5781 which also works with HTTPS proxies.

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

Successfully merging this pull request may close these issues.

None yet