Bug 225861 - Content Blocker: add a new action type - "scriptlet"
Summary: Content Blocker: add a new action type - "scriptlet"
Status: NEW
Alias: None
Product: WebKit
Classification: Unclassified
Component: WebCore Misc. (show other bugs)
Version: WebKit Nightly Build
Hardware: Unspecified Unspecified
: P2 Normal
Assignee: Nobody
URL:
Keywords: InRadar
Depends on:
Blocks:
 
Reported: 2021-05-17 03:12 PDT by Andrey Meshkov
Modified: 2023-04-27 02:00 PDT (History)
9 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Andrey Meshkov 2021-05-17 03:12:19 PDT
Popular content blockers like AdGuard, uBlock Origin, and others provide an option to run simple scripts on a website. The list of scripts that can be used is short and limited in what can be done to the page, but still, this is crucial to block ads on some websites.

The overall number of the "scriptlet" rules: almost 3000 in AdGuard filters and over 6000 in uBlock filters.

The most pressing issue we have due to the lack of scriptlets functionality provided by Safari is Youtube ads. We have to use a pretty limited approach and basically block all short videos. This does block ads, but there may be false positives and overall it hurts user experience.

Here's how YT ads are tackled with the help of scriptlet rules:

    youtube.com,youtube-nocookie.com##+js(json-prune, [].playerResponse.adPlacements [].playerResponse.playerAds playerResponse.adPlacements playerResponse.playerAds adPlacements playerAds)
    youtube.com,youtube-nocookie.com##+js(set, ytInitialPlayerResponse.adPlacements, undefined)
    youtube.com,youtube-nocookie.com##+js(set, playerResponse.adPlacements, undefined)

Scriptlets libraries are rather huge:
https://github.com/gorhill/uBlock/wiki/Resources-Library
https://github.com/AdguardTeam/Scriptlets

However, it would be great if Safari provided at least the very basic ones.

Here's the list of scriptlets which cover ~80% of existing rules:

1. "set-constant" - https://github.com/AdguardTeam/Scriptlets/blob/master/wiki/about-scriptlets.md#set-constant
2. "json-prune" - https://github.com/AdguardTeam/Scriptlets/blob/master/wiki/about-scriptlets.md#json-prune
3. "abort-current-inline-script" - https://github.com/AdguardTeam/Scriptlets/blob/master/wiki/about-scriptlets.md#abort-current-inline-script
4. "abort-on-property-read" - https://github.com/AdguardTeam/Scriptlets/blob/master/wiki/about-scriptlets.md#abort-on-property-read
5. "abort-on-property-write" - https://github.com/AdguardTeam/Scriptlets/blob/master/wiki/about-scriptlets.md#abort-on-property-write
Comment 1 Maciej Stachowiak 2021-05-20 12:59:57 PDT
I know this is a lot to ask, but can you give some examples of cases where each of these top 5 script rules are used AdGuard or uBlock filters, ideally with some explanation of why the rules are necessary and how they accomplish their goal?

Unlimited versions of these actions would defeat the security and privacy goals of Content Blockers, so we'd want to think about whether there are ways to achieve the same goal with narrower actions.
Comment 2 Andrey Meshkov 2021-05-21 01:49:22 PDT
(In reply to Maciej Stachowiak from comment #1)
> I know this is a lot to ask, but can you give some examples of cases where
> each of these top 5 script rules are used AdGuard or uBlock filters, ideally
> with some explanation of why the rules are necessary and how they accomplish
> their goal?

Got it, I'll get a list with some examples soon.

> Unlimited versions of these actions would defeat the security and privacy
> goals of Content Blockers, so we'd want to think about whether there are
> ways to achieve the same goal with narrower actions.

Could you please explain what possible threats you're seeing with them?

IMO, the only thing that *might* be problematic to an extent is `set-constant`, but with the limitation on possible values, the risk is minimal.
Comment 3 Andrey Meshkov 2021-05-21 03:12:48 PDT
(In reply to Maciej Stachowiak from comment #1)
> I know this is a lot to ask, but can you give some examples of cases where
> each of these top 5 script rules are used AdGuard or uBlock filters, ideally
> with some explanation of why the rules are necessary and how they accomplish
> their goal?

Here are some examples. Please let me know if you need more.

`youtube.com,youtube-nocookie.com##+js(json-prune, [].playerResponse.adPlacements [].playerResponse.playerAds playerResponse.adPlacements playerResponse.playerAds adPlacements playerAds)`

YouTube loads video metadata JSON alongside ads metadata in a single request. This rule removes parts of the JSON that contain ads meta.

Note, that json-prune scriptlet overrides two functions in order to intercept those JSON's:

* `JSON.parse`
* `Response.prototype.json`

`youtube.com,youtube-nocookie.com##+js(set, ytInitialPlayerResponse.adPlacements, undefined)`

When you load a YouTube page with a video for the first time, there's a JSON object `ytInitialPlayerResponse` initialized inside an inline script. This object contains ads metadata which this rule removes.

`[many domains...]#%#//scriptlet("abort-on-property-write", "_pop")`

Aborts a popular script for popup domains. They use random domains and this scriptlet takes care of it for good even when domain is not blocked yet.

Example: gledajcrtace.xyz

`[many domains...]#%#//scriptlet("abort-on-property-read", "BetterJsPop")`

Aborts another very popular script to show popup ads. Usually, used as an inline script.

Example: https://upvideo.to/v/jfiqnfdkwqpd

`dobreprogramy.pl,open.fm,abczdrowie.pl,www.o2.pl,parenting.pl,fotoblogia.pl,gadzetomania.pl,komorkomania.pl,autocentrum.pl,autokult.pl,pudelek.pl,wiadomosci.wp.pl,moto.wp.pl,pogoda.wp.pl,fitness.wp.pl,turystyka.wp.pl,wroclaw.wp.pl,wawalove.wp.pl,opinie.wp.pl,tech.wp.pl,sportowefakty.wp.pl,kobieta.wp.pl,finanse.wp.pl#%#//scriptlet("abort-on-property-write", "Object.prototype.callBids")`

Aborts an ad script on wp.pl domains. wp.pl uses random domains to serve ads and has random names of classes/ids elements, so it's not possible to block these ads requests/hide ads using common cosmetic rules.

`[many domains...]#%#//scriptlet("set-constant", "puShown", "true")`

Prevents popups/popunders from showing on many Turkish (not only, but mainly) websites. Sometimes it's an inline script, sometimes it's not, and sometimes it's a script with a random path.

Example (NSFW): filmkuzusu.com

`videox24.com#%#//scriptlet("json-prune", "MU_ads")`

Disables ads by removing "MU_ads" flag from the JSON loaded from iplay.videox24.com/api/api_movie.php?... URL.
Blocking ad URLs instead will either break the player or make user wait for the ad duration.

Example (NSFW): http://iplay.videox24.com/player?id=5350

`tvn24.pl#%#//scriptlet("json-prune", "playlist.movie.advertising.ad_server")`

Prevents video ads without breaking the player. Video player is initialized in an inline script (look for "window.VideoManager.initVideo") with ads metadata passed as a string. json-prune removes a part of this metadata.

Example: https://fakty.tvn24.pl/
Comment 4 Radar WebKit Bug Importer 2021-05-24 03:13:14 PDT
<rdar://problem/78393154>
Comment 5 Michael Catanzaro 2021-08-10 15:41:52 PDT
I'm going to try to nudge discussion along a bit.

> 3. "abort-current-inline-script" - https://github.com/AdguardTeam/Scriptlets/blob/master/wiki/about-scriptlets.md#abort-current-inline-script
> 4. "abort-on-property-read" - https://github.com/AdguardTeam/Scriptlets/blob/master/wiki/about-scriptlets.md#abort-on-property-read
> 5. "abort-on-property-write" - https://github.com/AdguardTeam/Scriptlets/blob/master/wiki/about-scriptlets.md#abort-on-property-write

These three might be a reasonable starting point. One could argue that these are unlikely to cause worse privacy or security problems than simply blocking scripts from executing in the first place. Of course, that may not actually be true for a reasonably-complex website, but we could claim that the content blockers are designed to be "secure" provided that websites don't do something "insecure" when a script execution gets terminated early.

Of course, there's going to be some performance cost to implementing this, but I assume it could be done way faster if implemented as a feature of JSC relative to implementing it via a user script.

> 1. "set-constant" - https://github.com/AdguardTeam/Scriptlets/blob/master/wiki/about-scriptlets.md#set-constant
> 2. "json-prune" - https://github.com/AdguardTeam/Scriptlets/blob/master/wiki/about-scriptlets.md#json-prune

If the content blockers are really meant to be seriously untrusted, then these both seem *really* unlikely. At least I wouldn't want untrusted code messing with constants or JSON on my bank's website.

(In reply to Maciej Stachowiak from comment #1)
> Unlimited versions of these actions would defeat the security and privacy
> goals of Content Blockers, so we'd want to think about whether there are
> ways to achieve the same goal with narrower actions.

How untrusted are content blockers really intended to be?

I'm a little skeptical that it makes sense to consider the content blockers to be completely untrusted, since most users will use just one or two popular filters, like EasyList or whatever. And if developers who use content blockers are reporting that they're not flexible enough to block the content they want to block, that probably indicates we need a design rethink.