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

Proxy issue with system proxy and Https Proxy agent #298

Open
samuel-deal-tisseo opened this issue Mar 21, 2024 · 2 comments
Open

Proxy issue with system proxy and Https Proxy agent #298

samuel-deal-tisseo opened this issue Mar 21, 2024 · 2 comments

Comments

@samuel-deal-tisseo
Copy link

If a system defined proxy and an explicit proxy config, requests failed using axios.

I'm not sure if it's an Axios or a httpsAgent issue (or that I don't use those two library correctly).

Example:

Given the following configuration

import { parse as parseURL } from "url";
import axios from 'axios';
import { HttpsProxyAgent } from 'https-proxy-agent';
import { HttpProxyAgent } from 'http-proxy-agent';

class PatchedHttpsProxyAgent extends HttpsProxyAgent {
	async connect(req, opts) {
		const url = parseURL(req.path);
		url.port = Number(url.port) || (url.protocol.includes('https') ? 443 : 80);
		return super.connect(req, { ...opts, ...url });
	}
}

function proxyObjToStr(proxyConf) {
	return proxyConf.protocol+"://"+proxyConf.host+":"+proxyConf.port.toString();
}

function test_req(url, proxyConf, applyPatch) {
	let request = {
		method: 'get',
		url: url,
		responseType: 'string',
		httpAgent: new HttpProxyAgent(proxyObjToStr(proxyConf)),
		httpsAgent: new HttpsProxyAgent(proxyObjToStr(proxyConf)),
		proxy: proxyConf
	};
	if (applyPatch) {
		request.proxy = {}
		request.httpsAgent = new PatchedHttpsProxyAgent(proxyObjToStr(proxyConf));
	}
	const axiosInstance = axios.create();
	const test_descr= url + (applyPatch ? " [patched]: " : " [current]: ");
	return axiosInstance(request).then(function (response) {
		console.log(test_descr + 'Ok');
	}).catch(function (error) {
		console.log(test_descr + "KO");
		if (error.response) {
			console.log({
				http_head: error.response.request._header.split("\r\n")[0],
				path: error.response.request.path,
				host: error.response.request.host
			});
		}
	});
}

async function main() {
	process.env["HTTPS_PROXY"] = "http://implicit.proxy:8080";
	const proxyConf = {
		protocol: 'http',
		host: 'explicit',
		port: 9000
	};
	await test_req("http://neverssl.com", proxyConf, false);
	await test_req("https://www.example.com/", proxyConf, false);
	await test_req("http://neverssl.com", proxyConf, true);
	await test_req("https://www.example.com/", proxyConf, true);
}

await main();

I have the following results:

http://neverssl.com [current]: KO
{
  http_head: 'GET http://neverssl.com:8080/ HTTP/1.1',
  path: 'http://neverssl.com:8080/',
  host: implicit.proxy'
}
https://www.example.com/ [current]: KO
{
  http_head: 'GET https://www.example.com:8080/ HTTP/1.1',
  path: 'https://www.example.com:8080/',
  host: 'implicit.proxy'
}
http://neverssl.com [patched]: Ok
https://www.example.com/ [patched]: Ok
samuel-deal-tisseo added a commit to samuel-deal-tisseo/bruno that referenced this issue Mar 21, 2024
This patched have been tested with http proxy:
* on http requests
* on https requests
* on proxy auth with basic auth
* on proxy without auth
* on tinnyproxy proxy
* on squid proxy

It should have no effects on SOCK proxy (And I don't know if the issue exists on those config anyway)

Given the following configuration
* System proxy: http://system.proxy:8080
* Bruno proxy: http://explicit.proxy:9000

On http request (to http://neverssl.com): it try to send the http request
to http://neverssl.com:8080 (wrong port) via the proxy http://explicit.proxy:9000 (correct proxy)

On https request (to https://www.example.com): it try send a CONNECT ::1 request (can be seen with wireshark)

An issue is opened on the proxy-agent repo: TooTallNate/proxy-agents#298
even tho I don't know if it's an axios issue, a proxy-agent issue or a bruno issue

```javascript
import { parse as parseURL } from "url";
import axios from 'axios';
import { HttpsProxyAgent } from 'https-proxy-agent';
import { HttpProxyAgent } from 'http-proxy-agent';

class PatchedHttpsProxyAgent extends HttpsProxyAgent {
	async connect(req, opts) {
		const url = parseURL(req.path);
		url.port = Number(url.port) || (url.protocol.includes('https') ? 443 : 80);
		return super.connect(req, { ...opts, ...url });
	}
}

function proxyObjToStr(proxyConf) {
	return proxyConf.protocol+"://"+proxyConf.host+":"+proxyConf.port.toString();
}

function test_req(url, proxyConf, applyPatch) {
	let request = {
		method: 'get',
		url: url,
		responseType: 'string',
		httpAgent: new HttpProxyAgent(proxyObjToStr(proxyConf)),
		httpsAgent: new HttpsProxyAgent(proxyObjToStr(proxyConf)),
		proxy: proxyConf
	};
	if (applyPatch) {
		request.proxy = {}
		request.httpsAgent = new PatchedHttpsProxyAgent(proxyObjToStr(proxyConf));
	}
	const axiosInstance = axios.create();
	const test_descr= url + (applyPatch ? " [patched]: " : " [current]: ");
	return axiosInstance(request).then(function (response) {
		console.log(test_descr + 'Ok');
	}).catch(function (error) {
		console.log(test_descr + "KO");
		if (error.response) {
			console.log({
				http_head: error.response.request._header.split("\r\n")[0],
				path: error.response.request.path,
				host: error.response.request.host
			});
		}
	});
}

async function main() {
	process.env["HTTPS_PROXY"] = "http://implicit.proxy:8080";
	const proxyConf = {
		protocol: 'http',
		host: 'explicit',
		port: 9000
	};
	await test_req("http://neverssl.com", proxyConf, false);
	await test_req("https://www.example.com/", proxyConf, false);
	await test_req("http://neverssl.com", proxyConf, true);
	await test_req("https://www.example.com/", proxyConf, true);
}

await main();
```

Here the following result:

```
http://neverssl.com: KO
{
  http_head: 'GET http://neverssl.com:8080/ HTTP/1.1',
  path: 'http://neverssl.com:8080/',
  host: 'implicit.proxy'
}
https://www.example.com/: KO
{
  http_head: 'GET https://www.example.com:8080/ HTTP/1.1',
  path: 'https://www.example.com:8080/',
  host: 'implicit.proxy'
}
http://neverssl.com [patched]: Ok
https://www.example.com/ [patched]: Ok
```
@TooTallNate
Copy link
Owner

I'm afraid I don't really understand what you're describing. Do you think you could submit a failing test case as a pull request? Also, try to take axios out of the equation to rule out some kind of issue with that package.

@raphendyr
Copy link

I think you are misconfiguring axios. The code here loads the proxy variable from the environment: https://github.com/axios/axios/blob/v1.x/lib/adapters/http.js#L77

You need to use false, i.e., request.proxy = false.

Please note that "proxy" in axios means "relay my request" or "man in the middle attack". In contrast, https-proxy-agent implements a tunnel or "HTTP CONNECT". These are two totally different methods with totally different implications.

In other words, do not user proxy from axios and always set it to false. It's likely never what you want (for anyone reading this).

Furthermore, note that the http-proxy-agent implements the relay method too. In other words, you want to use HttpsProxyAgent for both httpAgent and httpsAgent (it can be the same instance to my understanding).

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

3 participants