Ublock: Site CSP's prevent surrogates from being loaded. google-analytics on Twitter for example

Created on 26 Jul 2017  路  8Comments  路  Source: gorhill/uBlock

When I go to https://twitter.com with uBlock enabled I see

Refused to load the script 'data:application/javascript;base64,KGZ1bmN0aW9uKCkgewoJLy8gaHR0cHM6Ly9kZXZl鈥ecause it violates the following Content Security Policy directive: "script-src https://connect.facebook.net ... https://www.google-analytics.com 'nonce-IXZr3HyzACNQVWtSHdlFsQ==' 'self'".

Decoding some of the stuff in the error gives:

atob('KGZ1bmN0aW9uKCkgewoJLy8gaHR0cHM6Ly9kZXZlbG9wZXJzLmdvb2dsZS5jb20vYW5hbHl0aWNzL2Rldmd1aWRlcy9jb2xsZWN0aW9uL2FuYWx5dGljc2pzLwoJdmFyIG5vb3BmbiA9IGZ1bmN0aW9uKCkgewoJCTsKCX07Cgl2YXIgbm9vcG51bGxmbiA9IGZ1bmN0aW9uKCkgewoJCXJldHVybiBudWx')

(function() {
    // https://developers.google.com/analytics/devguides/collection/analyticsjs/
    var noopfn = function() {
        ;
    };
    var noopnullfn = function() {
        return nul

Which shows it's from the google analytics surrogate.

One or more specific URLs where the issue occurs

https://twitter.com/

Screenshot in which the issue can be seen

ublock-twitter

Steps for anyone to reproduce the issue

go to twitter.com while logged in
look at the console

Your settings

[If you fail to provide this info, I will mark the issue as invalid. Lists all settings which differs from default settings]

  • OS/version: arch linux 4.1.9
  • Browser/version: chrome v 56
  • uBlock Origin version: 1.13.8
Your filter lists

I've never touched these, the defaults I guess



Basically the sites CSP prevents loading scripts with data URI's.

I've been looking in to how to fix this for Privacy Badger, see this issue. There is a similar unsolved problem for Decentraleyes see here (cc @synzvato).

Here is a dump of notes on the topic, info from others is welcome:

can we modify the CSP to make it work?

We'd have to add a nonce or a hash of the redirected content. This would need to be done when we see the maine_frame of the document, which is before we know what we'd need to block. So we don't know ahead of time what tag would have to get the nonce. I also don't know what script would get surrogated, so I don't know its hash.

Is there another way?

Maybe redirect to something other than a data URI?

Would this still have CSP issues?
Maybe I could redirect to a file. But managing a bunch of surrogates in induvidual files sounds like a PITA. I'd also like to dynamically generate surrogates eventually.

Could I use a filesystem api to generate the files on the fly? Could I make a "fake" file? idk

Maybe I could redirect to a proxy file that receives messages from the extension, then dynamically defines the surrogate script? This probably cause raceconditions since the scripts' names are not immediately defined. I should try chrome.tabs.executeScript(..., 'document_start').

Chrome vs Firefox

Chrome requires that blocking webrequest listeners return a value like {foo: bar}, however Firefox allows you to return a promise.

This means that in chrome your blocking webrequest cannot depend on an async function to get its result. But in firefox you can.

So in FF but not Chrome, we could wait to inject a script, and for the script to signal back when it is ready.

https://developer.chrome.com/extensions/webRequest
https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/webRequest

Other ideas?

Most helpful comment

I don't plan to have uBO lower CSP rules set by a site. In my opinion, being able to inject a surrogate is less important than not relaxing existing CSP ruleset.

All 8 comments

I don't plan to have uBO lower CSP rules set by a site. In my opinion, being able to inject a surrogate is less important than not relaxing existing CSP ruleset.

@gorhill To be clear, I'm not suggesting that we lower the CSP for a site. We should not have to make a compromise like that to inject surrogates.

I always assumed this could be fixed by using web_accessible_resources, but this would allow a site's javascript code to precisely identify that uBO is in use, and another problem is that I would no longer be able to add/remove/modify/fix surrogate scripts without releasing a new version of the extension, the surrogates would need to be declared in the manifest.

I should try chrome.tabs.executeScript(..., 'document_start')

This won't work, the script will be executed in the content script (isolated) world.

I filed a chrome bug. I don't think a website's CSP should apply redirects caused by webextensions. https://bugs.chromium.org/p/chromium/issues/detail?id=749236

@gorhill re: that won't work:
I was imagining something like:

function runInWebsite(code) {
  let uri = makeDataUri(code),
    injected = 'document.write(\"<script src=' + uri + '></script>\");';
  chrome.tabs.executeScript(..., injected,  'document_start');
}

which would run code in the content script that injects the desired script.

Privacy Badger and it's user's would appreciate it if you could advocate for getting this bug fixed on the chrome issue tracker. I think your voice might help prioritize it.

https://bugs.chromium.org/p/chromium/issues/detail?id=749236#c5

Fixed with 17930cc778c2.

@cowlicks

I always assumed this could be fixed by using web_accessible_resources, but this would allow a site's javascript code to precisely identify that uBO is in use

I worked around this issue by requiring a fetch to any of the web accessible resources ("WAR") to be made with a valid secret token -- which secret token is initialized at extension launch time with a random value.

As long as the WAR are only used internally extension-side, and never exposed to the DOM, then I see no way for the web pages to be able to see these WAR, and thus no way to directly detect the extension through its WAR.

The access to the content of the /web_accessible_resources/ folder is controlled by a webRequest.onBeforeRequest listener. The listener will redirect to a non-web accessible resource when it fails to find the secret in the URL of the resource being fetched.

Now regarding:

another problem is that I would no longer be able to add/remove/modify/fix surrogate scripts without releasing a new version of the extension, the surrogates would need to be declared in the manifest.

I only import as "web accessible resources" those which are to be used for redirection purpose. At this point these resources used specifically for redirection purpose change very rarely[1], less frequently than the extension itself is updated, so I found acceptable to forfeit the ability to dynamically update these specific resources.


[1] Last time was more than four months ago.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ghost picture ghost  路  3Comments

UnicornVariant picture UnicornVariant  路  3Comments

GSNord picture GSNord  路  3Comments

RoxKilly picture RoxKilly  路  4Comments

Darkspirit picture Darkspirit  路  4Comments