DNR permission should be implicit when host permissions were accepted to avoid requesting excessive permissions

469 views
Skip to first unread message

World_Languages

unread,
Aug 7, 2021, 5:57:44 PM8/7/21
to Chromium Extensions
Currently, declarativeNetRequest has 2 extremes:
1. not being able to block any URLs, by simply not requesting the declarativeNetRequest permission. chrome.declarativeNetRequest returns undefined in the background page/service worker in this case.
2. being able to block any URLs from any origin by any initiator, by requesting the declarativeNetRequest permission, which tells the user the extension will be able to "block content on any page you visit". Additionally, redirect and modifyHeaders capabilities can be used if host permissions are available for those origins.

This might make sense at the first glance, but is flawed for many use cases where a host permission is inherently necessary, and specially when we take modifyHeaders into account.

Let's say I have an extension that uses the chrome.alarms API in the background service worker to periodically check if the user has unread notifications in example.com by fetching example.com/api/notifications every 1 minute, and uses chrome.notifications for telling the user there's new notifications.
It is clear that my extension requires the host permission to work, and cannot be converted to some other permission model, such as activeTab.
At this point, this extension requires a host permission for `https://example.com/*` and a required `notifications` permission. I am aware that soon, host permissions will be "optional by default", so in the future my extension would need to prompt the user to enable the host permission just after install. I want to make it clear that whether host permissions are enabled on install or not does not change the point I am about to make.

Let's say I want example.com/page1 to redirect to example.com/page2. This can be done with a content script, but it would redirect faster to use DNR, and would provide a better experience. Even though my extension already has a host permission for example.com, which is both the initiator and origin of the request, I cannot use DNR unless I explicitly request the declarativeNetRequest permission. But if I request that permission, I could now theoretically... block images with src `https://img.service.example/*` from loading on Reddit? And by using DNR I am required to ask extension users to please let the extension "block content on any page you visit". This was not the case with webRequestBlocking. I would probably just use a JS based redirect and provide a worse experience, otherwise, I'd need to explain to my users that I need to block content to provide a redirect, which is a weird thing to say.

Let's now say example.com updated their security and returns 403 for URL example.com/api/notifications unless the Referer header is set to `https://example.com/notifications`. With webRequestBlocking, modifying headers for a origin requires host permissions for it. DNR has that same requirement *and* also requires you request the declarativeNetRequest permission in the manifest.
So, same problem as above. I need to choose between having a non functioning extension by not requesting the permission for DNR, or I need to ask for excessive permissions and explain the user why I'm asking to block content on _any_ page they visit.

There are tons of situations where host permissions are required for an extension to minimally work, mostly because of security HTTP headers. If the extension already has host permissions for the initiator and the origin (or if the initiator is the background service worker), why does the extension need to ask for excessive permissions?

This problem is more important for extensions that already existed before DNR existed, excluding general content blockers. Content blockers are trading <all_urls> for declarativeNetRequest, which is great!
But extensions that have always needed and will always need a specific host permission to minimally work, are in a strange situation. They can continue to run arbitrary JavaScript in those websites, but they cannot block, redirect or modify headers without requesting excessive permissions. WRB did allow them to do this, so inevitably, these extensions will try to delay their migration to manifest V3 as long as possible. For these extensions, DNR removes no permissions, but it adds one. Even if you're doing the same thing as you were previously doing with WBR (e.g. spoof Referer header), because of the current design of DNR, you'll need to tell users "whoops, we can now block any content, but we promise not to".

DNR has been out for a while, but unless something is done about this, I bet we'll see lots of extensions rushing to update to manifest V3 before the deadline, having no other option but to request blocking capabilities when all they need is spoofing Referer, Origin or X-Frame-Options headers for them to work.

Michael Leggett

unread,
Aug 9, 2021, 2:22:57 PM8/9/21
to Chromium Extensions, World_Languages
I believe I have similar issues as the owner of a widely used extension that uses webRequestBlocking to block email open trackers in Gmail. From what I've read, DNR will give users more secure and performant extensions (yay). I seek to make it better for all and allow developers to ask for even less access where possible. 

The issues I see with moving to declarativeNetRequest:
  1. I do not want access to "Block content on ANY page". I only want permission to block content requested from mail.google.com. I don't want or need access to block content anywhere else. I'm not even sure if I really have that access (in which case, it is just a poorly written permission warning). Either way, this warning seems scary to me as a user –– Why does this extension that says it blocks email trackers want to be able to block content on every page I visit

  2. I do not want access to "Block [ANY] content on any page". Since Gmail proxies all images through googleusercontent.com/proxy/*, I only need the ability to block images that match known patterns loaded via googleusercontent.com/proxy/<tracker_image_url>. I suspect this is rare/unique to me and I wouldn't expect DNR to let me restrict my access in this way.

  3. Given the above, and given I already have permission to use webRequestBlocking, I do not want to prompt users to give me permission to declarativeNetRequest. Especially since that access seems (to the user) even broader than what I have now. And to make it worse, so that changing to MV3 is a non-blocking update, I will have to make this an optional permission too which means it will forever be an optional permission. 

Possible solutions:
  • As World_Languages posted, DNR could be granted for (and only for) the domains the extension already has access to. I would think this could mean that the scary "this extension can block content on any page" wouldn't be needed either.

  • If the host permission can't restrict where I can block content, could there be another field under rule_resources called, "origin" where I can restrict my access and hopefully make the permission the user sees less scary? 
Thoughts?

Thanks,
Michael

--
Added context (my manifest files):

Current MV2 manifest file:

{
  ...
  "manifest_version": 2,
  "content_scripts": [
    {
      "matches": ["https://mail.google.com/*"],
      "css": ["css/images.css", "css/simplifyGmail.css"],
      "js": ["js/simplifyGmail.js"],
      "run_at": "document_start",
      "all_frames": false
    }
  ],
  "permissions": [
    "storage",
    "webRequest",
    "webRequestBlocking",
    "*://mail.google.com/*",
  ],
  ...
)


Draft MV3 manifest file:

{
  ...
  "manifest_version": 3,
  "content_scripts": [
    {
      "matches": ["https://mail.google.com/*"],
      "css": ["css/images.css", "css/simplifyGmail.css"],
      "js": ["js/simplifyGmail.js"],
      "run_at": "document_start",
      "all_frames": false
    }
  ],
  "declarative_net_request": {
    "rule_resources": [
      {
        "id": "trackerList",
        "enabled": true,
        "path": "trackers.json"
      }
    ]
  },
  "permissions": ["storage", "declarativeNetRequest"],
  ...
}


Michael Leggett

unread,
Aug 9, 2021, 5:17:13 PM8/9/21
to Chromium Extensions, Michael Leggett, World_Languages
Short follow up: there is already something like my "origin" suggestion. You can add "domains": [ "example.com" ] to each rule. It seems tedious to add this to every rule, but whatever, it is supported. Yay! Or is it? I added this to all my rules as such:

trackers.json:
[
  ...
  {
    "id": 62,
    "action": { "type": "block" },
    "condition": {
      "urlFilter": "customeriomail.com/e/o",
      "resourceTypes": ["image"],
      "domains": ["mail.google.com"],
    }
  },
  ...
]

Even with this on every rule, the user still is warned that my extension can "Block content on any page." Maybe that is because the rules can be updated so maybe in the future I could block content on other domains? Is this working as intended?

World_Languages

unread,
Aug 13, 2021, 9:07:14 AM8/13/21
to Chromium Extensions, mleg...@gmail.com, World_Languages
> Even with this on every rule, the user still is warned that my extension can "Block content on any page." Maybe that is because the rules can be updated so maybe in the future I could block content on other domains? Is this working as intended?

That is correct. You can add dynamic URLs with JavaScript for any domain, so looking at the manifest is not enough to know what domains an extension can block content in.

Karan Bhatia

unread,
Aug 25, 2021, 3:48:58 PM8/25/21
to Chromium Extensions, worldxl...@gmail.com, mleg...@gmail.com
Thanks for reporting this issue. We are aware of this issue and plan to add a new declarativeNetRequest permission (without a permission message) to deal with this. 

-Karan
On behalf of the Chrome Extensions team.

Michael Leggett

unread,
Aug 25, 2021, 4:50:10 PM8/25/21
to Karan Bhatia, Chromium Extensions, worldxl...@gmail.com
YAAAAYYYY!! That is fantastic news!! Thank you so much!

Michael Leggett

unread,
Jan 24, 2022, 7:53:11 PM1/24/22
to Chromium Extensions, Michael Leggett, Chromium Extensions, worldxl...@gmail.com, karan...@chromium.org
It looks like declarativeNetRequestWithHostAccess was added in Chrome 96.

Is it safe to assume that when I upgrade to MV3, the user will not have to grant a new permission if I use declarativeNetRequestWithHostAccess AND the MV2 extension already had the host permission?

Thanks!
Michael

wOxxOm

unread,
Jan 25, 2022, 10:19:57 AM1/25/22
to Chromium Extensions, mleg...@gmail.com, Chromium Extensions, worldxl...@gmail.com, karan...@chromium.org
> when I upgrade to MV3, the user will not have to grant a new permission if I use declarativeNetRequestWithHostAccess AND the MV2 extension already had the host permission?

Yes, that's how it should work.

Michael Leggett

unread,
May 22, 2022, 10:25:06 AM5/22/22
to Chromium Extensions, wOxxOm, Michael Leggett, Chromium Extensions, worldxl...@gmail.com, karan...@chromium.org
First, thank you! I finally made the switch with the beta of my extension and plan to do so with the main version of my extension once I've confirmed that no one was prompted for accepting new permissions (they shouldn't be as I'm just swapping webRequest and webRequestBlocking for declarativeNetRequestWithHostAccess). I could only have done this with the addition of declarativeNetRequestWithHostAccess. 

One thing I found odd: while Chrome implicitly gives you host_permissions for the matching domain on content_scripts, that implicit permission does not extend to declarativeNetRequestWithHostAccess which requires you to explicitly ask for host_permissions on both the requesting domain and I think on the source domain as well. 

For me, this is fine as (1) I am blocking patterns that all funnel through a single proxy so the source domain is just one domain and (2) I already had access to both the source and requesting domain in the MV2 version of my extension that used webRequestBlocking. But it sure does make declarativeNetRequestWithHostAccess very narrow in scope.

A suggestion: I haven't fully considered the implications but I'd think it would be better if
(1) the implicit host_permission that you get from content_scripts should apply for declarativeNetRequestWithHostAccess
(2) you only needed access for the requesting domain, not the source domain (e.g., if my content script matches on mail.google.com, I can block any images that mail.google.com request). 

Let me know if I should post all of this elsewhere. And thank you again for engaging here and adding declarativeNetRequestWithHostAccess. 

Michael Leggett

unread,
May 27, 2022, 12:11:11 PM5/27/22
to Chromium Extensions, Michael Leggett, wOxxOm, Chromium Extensions, worldxl...@gmail.com, karan...@chromium.org
Follow up on this -- I read some more and now understand that the match patterns in content_scripts does is NOT intended to give you full host_permissions. It just no longer requires you to ask for host_permissions. So this is all working as intended and I just took all the talk about how I didn't need host_permissions any more to mean I also didn't need it for declarativeNetRequestWithHostAccess. 

馮韋元

unread,
Aug 22, 2022, 3:03:08 AM8/22/22
to Chromium Extensions, mleg...@gmail.com, wOxxOm, Chromium Extensions, worldxl...@gmail.com, karan...@chromium.org
I'm still seeing the permission warning when adding declarativeNetRequest, even though the other permissions are unchanged and I'm only replacing webRequest+webRequestBlocking with declarativeNetRequest. As it is, all users will get the extension disabled when migrating. 
My MV2 permissions:
"permissions": [
   "webRequest", "webRequestBlocking", "https://*.mydomain.com/*", "history", "tabs", "idle", "storage"
  ],
  "optional_permissions": ["<all_urls>"]

My MV3 permissions:
"host_permissions": ["https://*.mydomain.com/*"],
  "optional_host_permissions": ["<all_urls>"],
  "permissions": [
   "declarativeNetRequest", "storage", "history", "tabs", "idle"
  ],

Thanks in advance,
Francois

wOxxOm

unread,
Aug 22, 2022, 3:12:14 AM8/22/22
to Chromium Extensions, 馮韋元, mleg...@gmail.com, wOxxOm, Chromium Extensions, worldxl...@gmail.com, karan...@chromium.org
> I'm still seeing the permission warning when adding declarativeNetRequest

It's the correct behavior because this permission allows more than webRequest. To avoid the warning when upgrading from webRequest + <all_urls> you need to use declarativeNetRequestWithHostAccess in permissions and <all_urls> in host_permissions.
Reply all
Reply to author
Forward
0 new messages