Allowing insecure HTTPS requests in limited cases
There have been many requests to allow disabling HTTPS certificate checks. I pushed back on it, because strict checks are absolutely essential to HTTPS security (without them active MITM attackers can bypass all encryption, eavesdrop and modify traffic). I'm convinced that this such feature that could be enabled easily and globally is more dangerous than it sounds, and I wanted to provide a proper solution to this.
I think a proper solution would be a form of certificate pinning. Instead of disabling all security everywhere, you could say "Trust this particular certificate, even if it's mismatched or self-signed". However, I don't have time to implement it properly (and an implementation mistake here could be even worse than a global "fuck all security" setting, because it would give false impression of security), so I'm looking into simpler alternatives that still have some safety limits.
Here are some ideas (specific method names may change):
-
.alwaysTrustLocalhost()method, which disables HTTPS security onhttps://localhost,https://127.0.0.1,https://[::1]. This is expected to be safe, because loopback network is as safe as any of the code running on the machine. -
.ip("127.0.0.1")function that overrides connection IP address regardless of hostname in the URL (e.g.superagent.get("https://api.example.com").ip("127.0.0.1")would make localhost request withHost: api.example.comheader), which makesalwaysTrustLocalhost()work for it too.
I think these two would be helpful in development on a single machine, and perhaps some microservices on the same machine.
Question: should there be a way to trust a LAN as well?
superagent.disableAllSecurityInDevelopmentForDomains(["dev.example.com", "internal.example.com"]). A global switch to make HTTPS useless, but only for given domains, and only ifNODE_ENV=development. This way:
- Less likely to create a vulnerability if it's accidentally forgotten and deployed to production.
- In the worst case it will only compromise data of the listed domains (hopefully dev/test ones), and not others (e.g. if your server also makes requests to Google's APIs, it won't expose Google's credentials even if you chose to disable HTTPS security for your internal APIs).
- A method that disables HTTPS checks for all requests, including in production. I'd like to make it intentionally long and scary, so that it won't go unnoticed in code reviews of a short "fix" that made HTTPS errors go away:
superagent.disableAllHTTPSecurity({
allowAttackersToRemoveEncryption: true,
allowMaliciousModificationsOfTraffic: true,
})
Any news on this @kornelski?
In 4.1.0-beta I've added:
http://visionmedia.github.io/superagent/#testing-on-localhost
request.get(url)
.connect("127.0.0.1")
.trustLocalhost()
which allows you to force any HTTPS URL to connect to localhost (.connect(override IP)), and since the loopback connection is always safe by itself, HTTPS security on it can be safely broken (.trustLocalhost(true)).
I know this doesn't solve all cases yet, but hopefully helps some, and still doesn't create a footgun.
In 4.1.0-beta I've added:
http://visionmedia.github.io/superagent/#testing-on-localhost
request.get(url) .connect("127.0.0.1") .trustLocalhost()which allows you to force any HTTPS URL to connect to localhost (
.connect(override IP)), and since the loopback connection is always safe by itself, HTTPS security on it can be safely broken (.trustLocalhost(true)).I know this doesn't solve all cases yet, but hopefully helps some, and still doesn't create a footgun.
Locally it is working fine but when I run this setup on Codeship CI getting below error.
{ Error: connect ECONNREFUSED 0.0.0.0:3000
at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1191:14)
errno: 'ECONNREFUSED',
code: 'ECONNREFUSED',
syscall: 'connect',
address: '0.0.0.0',
port: 3000,
response: undefined }
In 4.1.0-beta I've added:
http://visionmedia.github.io/superagent/#testing-on-localhost
request.get(url) .connect("127.0.0.1") .trustLocalhost()which allows you to force any HTTPS URL to connect to localhost (
.connect(override IP)), and since the loopback connection is always safe by itself, HTTPS security on it can be safely broken (.trustLocalhost(true)).I know this doesn't solve all cases yet, but hopefully helps some, and still doesn't create a footgun.
Any idea what could be the resion @kornelski?