Qutebrowser: Set up QtWebChannel

Created on 2 May 2018  路  3Comments  路  Source: qutebrowser/qutebrowser

It turns out there's a lot of reasons why a QtWebChannel is needed. @jgkamat started some work on it but it turns out it wasn't needed at the time.

Possible usecases

  • Tracking keyboard focus accurately (#2668, https://github.com/parkouss/webmacs/blob/master/webmacs/scripts/setup.js)
  • Improve GreaseMonkey support (#3238, cc @toofar)
  • Maybe streaming pdfjs documents (#2330, #1557)
  • Support for cross-origin frames (#3569, #2329)
  • Better implementation for window.print() (#3495)

Security considerations and other open issues

  • If we have a QtWebChannel in the non-main JS world, it's fine to hook up any Python code to it, but we need to make absolutely sure there isn't some way to access it from the main world
  • If we have one in the main JS world (e.g. for window.print()), everything that is exposed via it can be called from the page.
  • In addition, there might be some (Python/Qt) magic which allows the page to call more than what we actively expose - if that's the case, we can't use it at all.
  • Qt/QtWebEngine had issues for a long time with QtWebChannels getting lost (on reload, with window.open(), etc. etc.) - are those all fixed in 5.7 or is this another reason to require 5.9 (#3839)?
2 - low

Most helpful comment

the only security hole it opens is one that has to be actively targeted and who is going to make a targeted attack against qutebrowser users?

That doesn't make it acceptable. A security hole is a security hole, and anything which exposes e.g. cross-origin XHR to pages will not land in qutebrowser's codebase, sorry.

Anyway, we could add a token to the greasemonkey script wrapper, save those on the python side, and check requests for a valid token.

If that's possible in a way nobody can listen on the channel (and find the token), sure. I doubt that's the case though... I guess another way (which works over an insecure channel) is JS somehow signing the messages. vise does something like this I think (also encrypting them), but that's a lot of hand-rolled crypto which I'm not really comfortable with either.

All 3 comments

I also did some work with QtWebChannel for getting cross-origin xml http requests working for greasemonkey scripts. I am planning on getting back to it at some point, I kinda stalled on it because the channel on the JS side was not reliably showing up but moving the scripts to be add to the page's script collection instead of the profile's will probably fix that (well, maybe not given your last bullet point), allowing for much easier development. It was added to my cross_origin_gm_xhr branch here https://github.com/toofar/qutebrowser/commit/75e7a2c62b6afce87b1ccb33fe54d1206b9f6b65

Functionally it works and I (and @nonamethanks) have been actively using it. It runs in the main JS world and isn't designed with security in mind. Since the design doesn't make accidental security policy violations likely (that is, it doesn't replace the builtin XMLHttpRequest object) the only security hole it opens is one that has to be actively targeted and who is going to make a targeted attack against qutebrowser users?
Anyway, we could add a token to the greasemonkey script wrapper, save those on the python side, and check requests for a valid token.

Edit: I should say I have no problem with that mess being refactored to instead register a command with a common bridge object and adjusting the javascript side to suit.

the only security hole it opens is one that has to be actively targeted and who is going to make a targeted attack against qutebrowser users?

That doesn't make it acceptable. A security hole is a security hole, and anything which exposes e.g. cross-origin XHR to pages will not land in qutebrowser's codebase, sorry.

Anyway, we could add a token to the greasemonkey script wrapper, save those on the python side, and check requests for a valid token.

If that's possible in a way nobody can listen on the channel (and find the token), sure. I doubt that's the case though... I guess another way (which works over an insecure channel) is JS somehow signing the messages. vise does something like this I think (also encrypting them), but that's a lot of hand-rolled crypto which I'm not really comfortable with either.

While the commit is two years old already, it looks like vise stopped using QtWebChannel because it was too broken, and instead uses some... interesting hacks: https://github.com/kovidgoyal/vise/commit/b61d3401126b794417ed4394b038233d0cd0d98f

Was this page helpful?
0 / 5 - 0 ratings