In Protest of the Web{*} Bulldozer

Venting my frustrations about new web standards

Tim K
7 min readMay 20, 2020
Come off it Mr. Dent. You can’t win, you know. You can’t lie in front of the bulldozer indefinitely.

A story cropped up this morning on my feed. Someone had discovered that while visiting eBay, their web browser was running a port scan on localhost with WebSockets. Presumably, the browser fed that information back to eBay, so they could do a risk assessment of some sort. Is the user a part of a fraud network?

Needless to say, this is mildly alarming. My web browser could be used to port scan my network? I try to follow security fairly closely, and I didn’t even know this could happen. What’s more, the scan just happened silently in the background, only visible to those who would happen to look for it.

I know enough web development to be dangerous… but to be honest, I haven’t read up on WebSockets. Could a malicious bit of JavaScript attack my desktop’s SSH server with a 0-day payload?

The answer is no, and yes. And I have some thoughts to add at the end.

This isn’t all THAT big deal…

After about half an hour of research, this is what I found.

First, I looked into whether WebSockets were as dangerous as I thought. Honestly, I didn’t know what they did, because I had no incentive to look into them until now. My initial fear was that WebSockets could be used to fire arbitrary packets at my computer or other devices on my network.

  • Firstly, WebSockets seem to be prohibited from accessing 192.168.0.0/16 and 10.0.0.0/8. In Firefox, it raises SecurityError. Odd that it can access localhost, but meh.
  • In Firefox, WebSockets can’t open to port 21, 22, or 23. The console spits back the same SecurityError. I was hoping that WebSockets would be blocked for privileged ports (< 1024), but it didn’t raise an error for port 24. It seems that Firefox maintains a blacklist? (I didn’t investigate this further, or build a complete list of ports.)
  • Finally, I ran a simple netcat listener on my machine, and opened a WebSocket to it. Netcat spit out an HTTP request with a few headers indicating it was a WebSocket. The console wouldn’t let me send data until the connection was established, either.

My fears were satisfied a bit. WebSockets only work on localhost, and you can’t send entirely arbitrary payloads. There are some restrictions to make that more difficult. Even still — I was able to replicate the author’s observation: WebSockets can definitely be used as a port scanner.

The next part was discovered by accident. I wanted to see if eBay would portscan me as well, and replicate that part of the author’s research.

  • I could not get eBay to port scan my computer, in either Firefox (with some privacy plugins like uBlock), or with a fresh Google Chrome browser. Even when logging in, I didn’t get port scanned.
  • Furthermore, I tried to open a WebSocket to localhost from the console while on eBay, but discovered it was blocked by a Content Security Policy — a header sent from the website. (Very curious! I had assumed it was some 3rd party script was doing the port scanning and eBay didn’t know… but it seems that whatever script that runs would need to work in conjunction with whatever sent the CSP!)

This is a bit of a neutral finding. Why isn’t localhost blocked by default? I can understand that may be use cases for it… perhaps some proprietary software that interfaces your browser with a daemon running on the computer. But that should be a requested permission, not something granted by default.

Wouldn’t you be concerned if a message popped up on your screen? “eBay wants to access the internal network on your computer. Allow access?”

A brief aside on port scanning

The author of the aforementioned article inferred that port scanning was a slightly offensive operation. I agree, but with one caveat.

If I place a computer on the public facing internet, port scans from anonymous users are fair game. Mainly, because if you point a web browser at my IP address to see if it responds… technically that’s a port scan! That isn’t malicious behavior, is it? I don’t want to try and write a law… you can check if ports are open, but only these ones, and only so fast. That just seems to violate the “zero, one, many” principle.

Things get a bit more gray if your port scanner starts sending arbitrary data to try and elicit more information from a service — like what version of software is running. Still though, fair game. If I have a service listening to the public internet, it should be designed to be resistant to abuse. I have to accept the risk that my daemon is vulnerable to a 0-day of some sort if I’m hosting it on the public internet.

If I don’t want to accept that risk, the answer is simple. Don’t open a port on the public internet. Either put up a firewall so it’s only accessible over VPN, or close it.

Port scanning is an entirely valid operation, and not necessarily malicious. But when a website is using my browser to traverse NAT and scan my local machine for open ports — that’s malicious behavior. Even if it’s done to “protect users”. My personal network is off limits. I can connect to you, but you can’t (and shouldn’t) connect to me without my explicit permission.

…but I’m still frustrated.

Over the past decade, I’ve watched the emergence of what I’ll refer to as Web{*} technology. It’s a bit of a cloudy, vague term… but I can give you some examples of it. (Though the curly braces don’t exist on the standards, I felt it helped illustrate my point better.)

  • Web{Sockets}: As mentioned in this article.
  • Web{Bluetooth}: Allows the browser to access Bluetooth devices through your computer
  • Web{RTC}: Enables your browser to do “real-time communication”
  • Web{Assembly}: Enables binary executables to run in your browser
  • Web{GL}: Allows your browser to communicate with your GPU
  • Web{USB}: Allows your browser to enumerate and communicate with USB devices. (Are you KIDDING me?!)
  • Web{???}: Allows your browser to access the accelerometers and other sensors on your system. At one point, it could read your battery charge status. (After particularly bad PR, the battery feature was deprecated.)

These technologies can be characterized in the following ways…

  • Each is enabled by default, and most people don’t know they even exist.
  • Each is difficult to disable, and likely lies hidden deep in about:config.
  • Each can be used to further fingerprint, identify, and exploit the user — but it seems that the feature developers either don’t think that this will happen, or don’t care. Perhaps it’s even their intention!
  • Each adds a MASSIVE layer of complexity to the browser. Anyone want to try an accelerometer based side channel attack to recover keyboard strokes in separate windows?
  • Each brings the browser closer and closer to my desktop, and seems solely driven by ChromeBook developers.
  • For the rest of the web, each is an unnecessary gimmick.

This can best be illustrated with the battery feature. Honestly, I can’t imagine why that feature is needed. At all. Facebook, Twitter, GMail… none of these need access to it. Even if I were developing some… full screen web based application for mobile, I don’t need to know the battery. The operating system displays that in a pull down menu for me, and will notify me if there’s a problem.

As a user, I don’t want redundant notifications. As a developer, I don’t care what’s happening on the user’s system. The “Web Battery API” has less utility than the infamous HTML <blink> tag. I can’t imagine the review process for how this got accepted as a web standard.

This leaves me feeling a little bit like Arthur Dent, waking up to find out that my house is being bulldozed, and this had all been the plan for months.

“But the plans were on display…”
“On display? I eventually had to go down to the cellar to find them.”
“That’s the display department.”
“With a flashlight.”
“Ah, well, the lights had probably gone.”
“So had the stairs.”
“But look, you found the notice, didn’t you?”
“Yes,” said Arthur, “yes I did. It was on display in the bottom of a locked filing cabinet stuck in a disused lavatory with a sign on the door saying ‘Beware of the Leopard.”

So, yes… WebSockets aren’t as big of a security risk as I had initially thought. Unlike the rest of the technologies, it seems to have somewhat of a purpose — even if it’s been made redundant by things like HTTP/2 streams. It’s a small change to deny localhost by default, and make the site request permission. But if you ask me, that’s a band-aid for a much bigger problem.

The problem is that once a Web{*} feature is “on-by-default”, it’s hard to roll it back. Give it a few months, and there will be some NodeJS fad where everyone wants to re-implement HTTP with WebSockets, and load every asset for their website through JavaScript to save a tenth of a microsecond in some edge case involving tech buzzword bingo. (What? I’d save much more time without this bloated framework? Shun the non-believer!) Once this happens, disabling WebSockets breaks the internet.

Now, if I want to have some modicum of control over what my browser does passively, I’ll need to install another plugin to control which sites use WebSockets. I’ll also need to revise my nginx config with Content Security Policies to deny the use of WebSockets on localhost, so that a malicious bit of JavaScript that lands on my website somehow can’t abuse my users.

This is just a mess. I’ve burned more than an hour of my time to understand how this affects me, and next week I’ll find that there’s another bulldozer coming in from another angle to lie down in front of. WebSockets can only connect… but now there’s WebSocketListener! Or how about WebRemoteDesktop! WebWiFiControl! WebCPUUsageMonitor! WebDMA! WebSmellovision!

--

--

Tim K

Tim builds circuit boards in Virginia Beach, and enjoys writing about current events, history, theology, and philosophy.