Open mikewest opened 3 years ago
There's a danger of us missing important ports because they're not used on the public internet.
For example, 3128, a common proxy port, is not on the above list. I don't know off the top of my head whether the bad port list is applied to proxies, or even whether it should be.
I'm assuming that the proxy configuration of a given user agent is outside the scope of Fetch, so I'm mostly concerned with requests triggered by websites.
I agree, though, that HTTP Archive data is going to miss both home networks and intranets. Perhaps we could add some telemetry to Chrome to get a more representative list? I think we could also handle the latter via enterprise policy and/or devtools carveouts for folks building websites (or an explicitly carved out range of ports we think are safe).
Will private networks be covered by https://github.com/wicg/private-network-access? Is it reasonable to require CORS preflights for requests to non-allow-listed ports?
Given that proxy autoconfig remains enabled by default on Windows, I think we'll likely need to continue using the same blacklist for proxies, in practice.
@yutakahirano:
Will private networks be covered by https://github.com/wicg/private-network-access?
Ideally, yes, but that seems somewhat orthogonal to the question here.
Is it reasonable to require CORS preflights for requests to non-allow-listed ports?
If we wanted to go this route, I think we could more simply require TLS for non-allowlisted ports. It seems to me that encryption would substantially mitigate the Slipstream style of attack.
@MattMenke2:
Given that proxy autoconfig remains enabled by default on Windows, I think we'll likely need to continue using the same blacklist for proxies, in practice.
I don't understand the risk here (because I know little to nothing about proxy configuration on Windows). Can a web-based attacker force a user to use a given proxy? That seems bad.
@MattMenke2:
Given that proxy autoconfig remains enabled by default on Windows, I think we'll likely need to continue using the same blacklist for proxies, in practice.
I don't understand the risk here (because I know little to nothing about proxy configuration on Windows). Can a web-based attacker force a user to use a given proxy? That seems bad.
If you're a man-in-the-middle attacker, you can respond to DNS lookups to wpad to get users to use your own PAC script. This feature that is only really targeted at enterprises is still enabled by default on all Windows machines, to the extent of my knowledge.
If you're a man-in-the-middle attacker, you can respond to DNS lookups to wpad to get users to use your own PAC script. This feature that is only really targeted at enterprises is still enabled by default on all Windows machines, to the extent of my knowledge.
Interesting. That sounds bad, but somewhat distinct from the risks leading us to slowly add ports to the bad port list, right? It seems like it would be totally possible to prevent websites from fetch()
ing a resource at port 3128, while at the same time allowing a proxy to be configured pointing at that same port. The contexts seem pretty distinct.
Once a PAC script is injected, it can make requests for http://some_host:80/ to http://local.domain:
Once a PAC script is injected, it can make requests for http://some_host:80/ to http://local.domain:
by setting that as a proxy for those requests. This would bypass both the port blacklist and any additional webby security features around connections to local IPs.
Malicious proxies are, indeed, bad. I agree that we need to deal with them in some way. All I'm saying here is that I'm not sure we need to deal with them via the bad port list.
Quick clarification: That's not a malicious proxy, but a malicious PAC script. There doesn't need to be any actual proxy in that scenario, the browser just needs to think it's using a proxy.
A preflight could protect vulnerable endpoints, but it couldn't protect vulnerable middleboxes, because in the Slipstream attack the server is also malicious and so can handle the preflight correctly.
Regarding the table: between Alt-Svc and SVCB/HTTPS, the bad port list needs to be applied not just at URLs, but also at the endpoint we actually connect to. Otherwise any protocol-confusion attacks can just as easily apply after the redirect.
I don't think either feature invalidates the numbers in the original report, since they're fairly rare and, for now, merely alternate routes one can safely ignore. (Though, with ECH in SVCB/HTTP, that will later no longer be the case.) But if the intent is to bound the use of arbitrary ports, which I agree seems prudent given all this mess, that's probably some feedback to the IETF that to stop building unbounded port redirection into everything. (@bemasc @ericorth FYI)
The other wrinkle is Alt-Svc and SVCB/HTTP specify not just TCP ports but also UDP ports for QUIC (@DavidSchinazi FYI). Protocols that run on the two ports don't coincide as much, so we may want to treat them differently? (Fortunately, QUIC is a lot less malleable than cleartext HTTP. Unfortunately, it probably still is malleable enough under chosen plaintext scenarios like the web. Fortunately most random protocols are TCP anyway.)
@davidben see #889 about potentially moving/duplicating the bad port list into "obtain a connection" (WebTransport might need to bypass though?).
I think we at least need to allow all the dynamic ports (49152-65535, RFC 6335). They're commonly used for short-lived servers, and shouldn't collide with existing semantics because they're explicitly non-registrable.
I'm trying to understand what the point of enshrining such a blocklist or allowlist in the long term is—I understand that it's useful for the web platform to be part of a coordinated incident response to individual vulnerabilities in this area, but isn't the ultimate responsibility on the NAT firewalls in question to close the hole created by their improper parsing of of these protocols? We're never going to fix this problem by blacklisting or allow-listing specific ports if the broken NAT and ALG system remain in place and continue to be developed. In that way, this type of attack is very similar to HTTP Request smuggling—there just isn't enough information on the client side to be able to block it comprehensively.
@nightpool I agree that NAT firewalls should fix their bugs, but it will be a very long time before all the deployed devices have been replaced. In the meantime, new devices will introduce new bugs.
Browsers are one of the few applications that run untrusted code inside people's internal networks. Users have an expectation that they can browse the web in safety and we (browser developers) have a responsibility to live up to that. If we fail to do so then users will stop browsing the web. My personal view is that that would be a great loss. This is why we keep working around other people's bugs.
Once we've added a port to the blocklist we never know if it's safe to remove it again, so in practice it will only grow. Every time we add something to the blocklist we break people's applications, so it's desirable if we can stop doing that.
Once we've added a port to the blocklist we never know if it's safe to remove it again, so in practice it will only grow. Every time we add something to the blocklist we break people's applications, so it's desirable if we can stop doing that.
Would this mean that the allowlist couldn't be expanded since we could similarly never know if it's safe to allow any currently blocked port?
I'm worried about the myriad of servers which run web interfaces on non-standard ports so as not to conflict with a webserver running on the same machine, e.g. cups 631, selenium grid 4444, goma 8088, plex 32400, tools like code-server (defaults to 8080) or cloud9 (defaults to 8181) specifically need to avoid dev web server ports as well since they're often used for working on that dev web content, etc. It's common to configure routers with a non-standard port for remote web configuration for the same reason. I suspect some IoT devices may use non-standard configuration ports.
Would a devtools configured exception be possible to use while not keeping devtools open (i.e. similar to adding an exception to your firewall)? I've seen many cases where the presence of devtools significantly slows down the site, and it's awkward to lose that screen real estate when you're not working on the site.
Alternately, could we get most of the benefit without some of the pain by not restricting the main navigation, but only restricting sub-resource requests (explicitly allowing them to the ip:port used for the main navigation)?
Would this mean that the allowlist couldn't be expanded since we could similarly never know if it's safe to allow any currently blocked port?
Yes, I think we would never add new ports to the allowlist, only remove them.
Would a devtools configured exception be possible to use while not keeping devtools open (i.e. similar to adding an exception to your firewall)? I've seen many cases where the presence of devtools significantly slows down the site, and it's awkward to lose that screen real estate when you're not working on the site.
So essentially it would be a normal browser setting, but hidden in devtools rather than on the usual setting page? It might work.
Alternately, could we get most of the benefit without some of the pain by not restricting the main navigation, but only restricting sub-resource requests (explicitly allowing them to the ip:port used for the main navigation)?
I think the security benefits of this are not that great, since you can perform many attacks just by using a form with POST. However, it might be a good transitional stage to get web developers used the idea of there being an allowlist.
Got reminded of this recently and noticed there was this discussion point that is worth touching on:
Is it reasonable to require CORS preflights for requests to non-allow-listed ports?
If we wanted to go this route, I think we could more simply require TLS for non-allowlisted ports. It seems to me that encryption would substantially mitigate the Slipstream style of attack.
CORS preflights and TLS limit the space significantly, but they don't fully solve the problem. They still assume that you and the other side are speaking the same protocol. When we send a preflight, we'll send OPTIONS /attacker/controlled/path HTTP/1.1
, or a TLS ClientHello with attacker-controlled server_name or session ticket. That those are attacker-controlled works because the syntaxes have defined meaning and we can assume the other side will correctly interpret those bytes as the path or server_name or whatever.
But when we don't even know we're speaking the same protocol as the other side, that breaks down. E.g. maybe your protocol is just newline-separated and you ignore unrecognized commands. While goofy, that's a perfectly well-defined protocol. (AIUI that's what memcached does.) Then any attacker-controlled field that can fit a newline (e.g. TLS session tickets) is an avenue for attack. Or if you use space-separated commands, OPTIONS /attacker/controlled/path HTTP/1.1
is a problem
Essentially the meaning of the port allowlist/blocklist is: anyone deploying anything on those ports must use protocols that cannot be confused with an HTTP-related protocol (that is, TLS and HTTP/1.1) in a cross-protocol attack. Browsers have squatted practically the whole port space, so we've rather constrained everyone else. An allowlist means we relinquish part of that space so other applications don't need to worry about HTTP.
Alternately, could we get most of the benefit without some of the pain by not restricting the main navigation, but only restricting sub-resource requests (explicitly allowing them to the ip:port used for the main navigation)?
I think the security benefits of this are not that great, since you can perform many attacks just by using a form with POST. However, it might be a good transitional stage to get web developers used the idea of there being an allowlist.
What if links and POST requests were only allowed so long as they matched the top-level port? I.e. allow the user to navigate to any port manually but content can only link to other resources served from the same port or allow listed ports?
I came across this via port 10080 and amanda for my prometheus exporter. Prometheus exporters speak HTTP/HTTPS, and when developing them it's common to use a web browser to see what's being returned.
Ports 9100-10013 are used by a prometheus exporter. Any one server will be only using a small fraction of those since each port is a different piece of software being monitored. I assume each one has had users setting it up who visited the exporter in a web browser to test, and developers will of done the same.
I also want to note that I know of several pieces of software that put up a HTTP server for users to use the software and don't have the port appear on the list in the first post.
Given the drip-by-drip expansion of the bad port list over time, I wonder whether it's reasonable to invert the list. Skimming through HTTP Archive, for example, ~99.94% of URLs requested are using the default port, and a substantial amount of the rest are specifying well-known ports like 8080, 8443, 444, 8090, 8081, 81, 8000, 443, and so on.
Given that we know there's real risk here, perhaps coming up with a feasible allowlist (with user-agent specific carveouts via devtools and/or enterprise policy) would be a good use of our time?
The following HTTP Archive query:
yields:
Based on this initial sampling, it might not be crazy to build an allowlist of the top XXX ports in actual usage today, and then cull it over time.
/cc @MattMenke2 @ricea @mozfreddyb @youennf to follow up on https://github.com/whatwg/fetch/pull/1148 and https://groups.google.com/a/chromium.org/g/blink-dev/c/kyVo08TtOp8/m/nu4B94LcCAAJ.