Add Websocket blocker to resource library #1497

Closed
neuronix opened this Issue Mar 22, 2016 · 16 comments

Comments

Projects
None yet
4 participants
@neuronix

Services like revdefender use websockets to load anti-adblocking scripts. Currently, Chrome does not allow extensions to monitor websocket communication. A workaround would be to inject a small script replacing the Websocket definition by a dummy implementation.

Unfortunately, custom scripts are not allowed, so this would have to be included in the resource library.

@ghost

This comment has been minimized.

Show comment
Hide comment
@ghost

ghost Mar 22, 2016

Services like revdefender use websockets to load anti-adblocking scripts.

Got any example links? Until now I only came across an undesirable websocket here: ws://go.wsockd.com:9000/?id=115535
Needs to be blocked by ||wsockd.com^$third-party in EasyList.

ghost commented Mar 22, 2016

Services like revdefender use websockets to load anti-adblocking scripts.

Got any example links? Until now I only came across an undesirable websocket here: ws://go.wsockd.com:9000/?id=115535
Needs to be blocked by ||wsockd.com^$third-party in EasyList.

@neuronix

This comment has been minimized.

Show comment
Hide comment
@neuronix

neuronix Mar 22, 2016

I just found a duplicate report here with an example: #956

However, please note that I am suggesting a real solution whereas in the original post there is none! Blocking inline scripts is unacceptable, dummy Websocket would be good.

I just found a duplicate report here with an example: #956

However, please note that I am suggesting a real solution whereas in the original post there is none! Blocking inline scripts is unacceptable, dummy Websocket would be good.

@lewisje

This comment has been minimized.

Show comment
Hide comment
@lewisje

lewisje Mar 22, 2016

How would you propose ensuring this dummy implementation actually replaces the existing WebSocket definition? It could well be defined inside a closure, so that it's not open to interpretation by extension code.

lewisje commented Mar 22, 2016

How would you propose ensuring this dummy implementation actually replaces the existing WebSocket definition? It could well be defined inside a closure, so that it's not open to interpretation by extension code.

@neuronix

This comment has been minimized.

Show comment
Hide comment
@neuronix

neuronix Mar 22, 2016

The aim is not to replace the Websocket instance used by the third party but to replace the actual definition of the Websocket class so that all instances have the appropriate methods but with no effect.

If the script is injected before all the others, they could not create a reference to the original object. You just need this kind of code (not exact, would need to check the Websocket API):
window.WebSocket = function WebSocket() { this.connect = function () {}; this.send = function () {} .... };

I have seen other people suggest such code:
var undefined; window.WebSocket = undefined;
But that could lead the third party code to use a polyfill or raise an error. The dummy code has the advantage of not raising errors and make the code fail silently.

Edit: precisions & code fixing.

The aim is not to replace the Websocket instance used by the third party but to replace the actual definition of the Websocket class so that all instances have the appropriate methods but with no effect.

If the script is injected before all the others, they could not create a reference to the original object. You just need this kind of code (not exact, would need to check the Websocket API):
window.WebSocket = function WebSocket() { this.connect = function () {}; this.send = function () {} .... };

I have seen other people suggest such code:
var undefined; window.WebSocket = undefined;
But that could lead the third party code to use a polyfill or raise an error. The dummy code has the advantage of not raising errors and make the code fail silently.

Edit: precisions & code fixing.

@lewisje

This comment has been minimized.

Show comment
Hide comment
@lewisje

lewisje Mar 22, 2016

To be extra secure, try something like

Object.defineProperty(window, 'WebSocket', {value: function WebSocket() {/* code */}});

that way, craftier anti-adblock mechanisms can't re-redefine it (though they could make a dummy iframe and pull out the .contentWindow.WebSocket from there, and apply it to the main window...)

lewisje commented Mar 22, 2016

To be extra secure, try something like

Object.defineProperty(window, 'WebSocket', {value: function WebSocket() {/* code */}});

that way, craftier anti-adblock mechanisms can't re-redefine it (though they could make a dummy iframe and pull out the .contentWindow.WebSocket from there, and apply it to the main window...)

@neuronix

This comment has been minimized.

Show comment
Hide comment
@neuronix

neuronix Mar 22, 2016

Didn't know about that, nice touch! :)

Didn't know about that, nice touch! :)

@lewisje lewisje referenced this issue in gorhill/uMatrix Apr 9, 2016

Closed

Allow to control non http connections as well #542

@laniakea64

This comment has been minimized.

Show comment
Hide comment
@laniakea64

laniakea64 Apr 17, 2016

make a dummy iframe and pull out the .contentWindow.WebSocket from there, and apply it to the main window

Nope, that trick would fail if this is implemented well. "Dummy" iframes have about:blank URL (at least in Gecko-based browser), so provided it's technically possible to making sure to apply the redefine to about:blank (and any equivalents on other browser-platforms) should make that moot.

make a dummy iframe and pull out the .contentWindow.WebSocket from there, and apply it to the main window

Nope, that trick would fail if this is implemented well. "Dummy" iframes have about:blank URL (at least in Gecko-based browser), so provided it's technically possible to making sure to apply the redefine to about:blank (and any equivalents on other browser-platforms) should make that moot.

@lewisje

This comment has been minimized.

Show comment
Hide comment
@lewisje

lewisje Apr 18, 2016

Maybe an ES6 Proxy could ensure that whenever a new frame is created, the implementation of WebSocket inside that frame is re-defined to be the dummy, but I'm not that well-versed in the use of Proxy traps.

lewisje commented Apr 18, 2016

Maybe an ES6 Proxy could ensure that whenever a new frame is created, the implementation of WebSocket inside that frame is re-defined to be the dummy, but I'm not that well-versed in the use of Proxy traps.

@lewisje lewisje referenced this issue in uBlockOrigin/uAssets Apr 18, 2016

Closed

Add WebSocket blocker to resource library #21

@laniakea64

This comment has been minimized.

Show comment
Hide comment
@laniakea64

laniakea64 Apr 18, 2016

Do Blink-based browsers not have an equivalent of Gecko's content-document-global-created observer notification?

Do Blink-based browsers not have an equivalent of Gecko's content-document-global-created observer notification?

@lewisje

This comment has been minimized.

Show comment
Hide comment
@lewisje

lewisje Apr 18, 2016

I believe that's only for extension code: This is code that gets injected into the page.

lewisje commented Apr 18, 2016

I believe that's only for extension code: This is code that gets injected into the page.

@laniakea64

This comment has been minimized.

Show comment
Hide comment
@laniakea64

laniakea64 Apr 18, 2016

Sorry, I wasn't being clear. Yes it's only for extension code - thing is, extension can't know to inject code into the page (or otherwise run code in page context) without some kind of listener. In Blink extensions, are such listeners limited to top-level window, thus forcing the injected code to do all the work finding and applying to any frames & sub-frames?

Sorry, I wasn't being clear. Yes it's only for extension code - thing is, extension can't know to inject code into the page (or otherwise run code in page context) without some kind of listener. In Blink extensions, are such listeners limited to top-level window, thus forcing the injected code to do all the work finding and applying to any frames & sub-frames?

@lewisje

This comment has been minimized.

Show comment
Hide comment
@lewisje

lewisje Apr 18, 2016

I think I understand what you're getting at: I presume that the Chrome extension API has this capability (although I haven't checked), and then the way to keep the attack I described from working might be to use a rule like *$subdocument,domain=bad.site,redirect=dummywebsocket

...but I just remembered something else, all of the redirect resources are replacing scripts that would have been loaded over the network, but this proposal is to replace a native browser API, so there's nothing to block-then-redirect.

Maybe this could instead be done with a new $websocket option that leads uBlock Origin to dummy out the WebSocket API.

lewisje commented Apr 18, 2016

I think I understand what you're getting at: I presume that the Chrome extension API has this capability (although I haven't checked), and then the way to keep the attack I described from working might be to use a rule like *$subdocument,domain=bad.site,redirect=dummywebsocket

...but I just remembered something else, all of the redirect resources are replacing scripts that would have been loaded over the network, but this proposal is to replace a native browser API, so there's nothing to block-then-redirect.

Maybe this could instead be done with a new $websocket option that leads uBlock Origin to dummy out the WebSocket API.

@gorhill

This comment has been minimized.

Show comment
Hide comment
@gorhill

gorhill Apr 18, 2016

Owner

Maybe this could instead be done with a new $websocket option that leads uBlock Origin to dummy out the WebSocket API.

I like this idea. Will see what I can do.

By the way, as a rule I prefer to investigate/write the code myself, it's just how it works best for me.

Owner

gorhill commented Apr 18, 2016

Maybe this could instead be done with a new $websocket option that leads uBlock Origin to dummy out the WebSocket API.

I like this idea. Will see what I can do.

By the way, as a rule I prefer to investigate/write the code myself, it's just how it works best for me.

@gorhill

This comment has been minimized.

Show comment
Hide comment
@gorhill

gorhill Apr 19, 2016

Owner

For the specific case raised here, http://putlocker.is/watch-better-call-saul-tvshow-season-1-episode-1-online-free-putlocker.html, the solution is this filter:

||oclasrv.com^$script,redirect=noopjs,domain=thevideos.tv

This prevent the blocked script from raising an error. A websocket is used when this the script from oclasrv.com is reported to the caller as blocked. Redirecting to an empty js file prevents the error condition.

This demonstrates how important it is to provide an actual case -- as a solution may already exist for it.

Owner

gorhill commented Apr 19, 2016

For the specific case raised here, http://putlocker.is/watch-better-call-saul-tvshow-season-1-episode-1-online-free-putlocker.html, the solution is this filter:

||oclasrv.com^$script,redirect=noopjs,domain=thevideos.tv

This prevent the blocked script from raising an error. A websocket is used when this the script from oclasrv.com is reported to the caller as blocked. Redirecting to an empty js file prevents the error condition.

This demonstrates how important it is to provide an actual case -- as a solution may already exist for it.

@gorhill gorhill closed this in 2d26d1d Apr 20, 2016

@gorhill

This comment has been minimized.

Show comment
Hide comment
@gorhill

gorhill Apr 20, 2016

Owner

Tested working with http://www.websocket.org/echo.html.

Owner

gorhill commented Apr 20, 2016

Tested working with http://www.websocket.org/echo.html.

gorhill added a commit that referenced this issue Apr 20, 2016

@gorhill

This comment has been minimized.

Show comment
Hide comment
@gorhill

gorhill Apr 20, 2016

Owner

The issue is not taken care through a resource in the resource library. There is a special script injected for Chromium-based browsers only, which script communicates with uBO's main process through a specially crafted http/https network request, which sole purpose is to let uBO evaluate the URL used for the websocket URL (that specially-crafted network request never leaves the browser). This allows to expose websocket connection attempts to the platform-independent code of uBO, hence static or dynamic filtering can block/allow websocket connections, and these will be reported in the logger like any other network requests.

Owner

gorhill commented Apr 20, 2016

The issue is not taken care through a resource in the resource library. There is a special script injected for Chromium-based browsers only, which script communicates with uBO's main process through a specially crafted http/https network request, which sole purpose is to let uBO evaluate the URL used for the websocket URL (that specially-crafted network request never leaves the browser). This allows to expose websocket connection attempts to the platform-independent code of uBO, hence static or dynamic filtering can block/allow websocket connections, and these will be reported in the logger like any other network requests.

gorhill added a commit that referenced this issue Apr 21, 2016

gorhill added a commit that referenced this issue Apr 21, 2016

@TheRyuu TheRyuu referenced this issue in gorhill/uBO-Extra May 9, 2016

Closed

Behavior with multiple extensions #1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment