Chrome extension bug that could be related to cross-origin permissions - google-chrome-extension

We run an extension that requires fetching and searching for data on multiple websites.
We have been using cross-origin XMLHttpRequests using Jquery, and have not faced an issue until now.
The asynchronous requests are being executed successfully. This has been the case even though we have not explicitly requested cross-origin permissions as suggested here: https://developer.chrome.com/extensions/xhr
This is what the relevant portions of our manifest currently look like:
{
"background" : {
"scripts": ["background.js"]
},
"permissions" : ["storage" ],
"content_scripts" : [
{
"matches" : ["<all_urls>"],
"js" : [ "jquery-2.0.0.min.js","jquery-ui-1.10.3.custom.min.js","date.js",
"file1.js","file2.js",
"fileN.js"],
"run_at" : "document_idle",
"all_frames" : false
},
],
"content_security_policy": "script-src 'self' https://ssl.google-analytics.com; object-src 'self'",
"web_accessible_resources" : [ "icona.png" , "iconb.png","iconc.png"],
"manifest_version": 2
}
Even though the permissions do not explicitly request access to urls from which data is asynchronously fetched, the extension has worked fine.
Off late, we have had a few complaints from users that the extension no longer works and no data is being displayed. We have not been able to replicate this issue in Chrome on Linux (Version 34.0.1847.132). The users who seem to be facing this issue seem to be using Mac OS X or, less frequently, Windows.
We cannot figure out why this issue is OS specific, or if that's a curious correlation.
If the problem is indeed one of wrong permissions, can we set the permission to
["http://*/","https://*/"]
without having the extension disabled automatically for manual re-enabling by the user?
We already require permissions for all urls through "matches" : ["<all_urls>"] Does this ensure that the addition of permissions as above will not trigger automatic disabling of the extension?

Chrome extensions allow for cross-origin requests, but you have to declare the hosts you want to access in the permissions section of your manifest. The matches section of content scripts shouldn't give you host permissions.
You should add host permissions to your manifest. I don't know what will happen on update. Considering that the user was already prompted to allow your extension access to all their web data, maybe your extension won't be disabled on update. You can simply test that by creating a testers only extension on the webstore with your original version, install it, update it, and see what happens.

Related

Chrome extensions (and/or tampermonkey scripts) not running on certain websites (like gmail)

I have a very simple chrome extension that refuses to run on some sites like https://mail.google.com. It runs fine on other sites which makes me think something is limiting extensions/scripts from running on some sites. The sample case is quite simple and listed below.
With this sample case I see "Hello world" in the developer console when I navigate to https://about.me. I also see the extension in the Developer Console's Execution Context Selector. However, when I navigate to https://mail.google.com I don't see the log entry or the extension in the Execution Context Selector.
I have tried something similar with tampermonkey and am not seeing that script run on gmail either. Thanks!
manifest.json:
{
"manifest_version": 2,
"name": "Gmail extension test",
"version": "0.1.9",
"description": "Try running inside gmail page",
"content_scripts": [{
"all_frames": true,
"js": ["content.js"],
"matches": [
"https://mail.google.com/*",
"https://about.me/*",
"http://*/*",
"https://*/*"
]
}]
}
content.js:
console.warn("Hello world");
Environment:
Chrome 66.0.3359.117
macOS 10.13.3 (17D102)
As #wOxxOm suggested. I tracked down the problem to the fact that my company has a Chrome policy set against running extensions on the google.com domain. I had no warning entries in the Developer Console or the macOS Console, I just tracked down other folks complaining about in an internal forum.
The policy that applies in this case is ExtensionSettings which is set in a OS/device specific way. To help diagnose this restriction, you can view your active polices in Chrome under chrome://policy/. In my case I had something like the following in my chrome://policy:
{
"*": {
...
"runtime_blocked_hosts": [ "*://*.google.com", ....]
},
I'm not aware of a generic workaround for this at the extension level. Instead I had to work with my company IT department to whitelist the extension.

User configurable url permissions in chrome extension

I am creating a chrome extension that adds an action with a global hotkey to JIRA. I can hard code the url for my own instance of JIRA into my extension, but I would like this url to be user configurable as other users will have different urls for their own JIRA instances.
I would like to know if there is a better way of doing this than just giving my extension permission for all urls and checking in my background script to compare the current url to the one the user has chosen as a setting. Ideally my background/inject script would only run on the users chosen url. I looked at the permissions api but can't figure it out.
My current manifest.json looks as follows, I have hard coded permission to my jira url, is there a way to make this permission user configurable?
{
"permissions": [
"contentSettings",
"storage",
"commands",
"http://myjiraurl/*"
],
"background": {
"matches": [
"http://myjiraurl/*"
],
"scripts": ["src/background/background.js"]
},
"content_scripts": [
{
"matches": [
"http://myjiraurl/*"
],
"js": [
"js/jquery.min.js",
"src/inject/inject.js"
]
}
]
}
Whatever you do, in order to inject into arbitrary hosts, you have to have http://*/ and https://*/ in your permissions, preferably optional permissions. Your proposal - comparing the current url with the one in the settings - sounds very reasonable: Just compare the current url with the one in the setting and make a chrome.permissions.request if it matches, silently stop running your code if it fails.
I can think of one work-around to avoid that, but honestly it's not giving you much:
Use http://*/ and https://*/ as optional permissions (you should really really make them optional anyway).
Make the chrome.permissions.request call at the time the user is modifying the options.
In your background script, make a chrome.permissions.contains call for the current url and silently stop running your code if there's no permission.
The result of the above is that instead of comparing the current url to the one in the setting, it will compare the current url with whatever the extension has previously got permission for. I guess it simplifies the background script a bit (you don't have to get the url stored in the settings), but makes the options page code a bit more complicated.

Why the extension with specific key declared can access chrome:// pages?

As we know, by default chrome extensions doesn't have access to chrome:// pages such as chrome://extensions and chrome://settings. ( Of course we can change chrome://flags/#extensions-on-chrome-urls flags however the following question is based on that we didn't change the default flags).
Recently I happen to find ChromeVox (offered by chrome.google.com) can work well in all pages including chrome:// pages. I checked the source code for this extension and find as long as we add the following line in manifest.json for any extension, the extension can work well in chrome:// pages.
"key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDEGBi/oD7Yl/Y16w3+gee/95/EUpRZ2U6c+8orV5ei+3CRsBsoXI/DPGBauZ3rWQ47aQnfoG00sXigFdJA2NhNK9OgmRA2evnsRRbjYm2BG1twpaLsgQPPus3PyczbDCvhFu8k24wzFyEtxLrfxAGBseBPb9QrCz7B4k2QgxD/CwIDAQAB"
So it looks like chrome has something like whitelist to allow specific extensions to break the default restrictions. Am I right? Is there official guide to clarify this behavior?
Appendix:
The following is a sample extension, you will find with the key, console will output test even in chrome://extensions pages; however once removing the key, nothing happens.
manifest.json:
{
"manifest_version": 2,
"name": "Test",
"version": "1.0",
"content_scripts": [
{
"matches": [
"<all_urls>"
],
"js": [
"content.js"
]
}
],
"key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDEGBi/oD7Yl/Y16w3+gee/95/EUpRZ2U6c+8orV5ei+3CRsBsoXI/DPGBauZ3rWQ47aQnfoG00sXigFdJA2NhNK9OgmRA2evnsRRbjYm2BG1twpaLsgQPPus3PyczbDCvhFu8k24wzFyEtxLrfxAGBseBPb9QrCz7B4k2QgxD/CwIDAQAB"
}
content.js:
console.log('test');
"key" property in manifest.json uniquely defines the extension's ID in encrypted form.
Some Google extensions are unfairly(?) whitelisted by ID in the source code of chromium.
In this case, ChromeVox:
scripting_whitelist_.push_back(extension_misc::kChromeVoxExtensionId);
And then this whitelist is checked to see whether an extension can run everywhere in PermissionsData::CanExecuteScriptEverywhere, which is accessed in CheckRestrictedUrls where we can see restricted schemes: chrome://, chrome-extension://, chrome-debugger://

Fetch API not sending session cookies when used inside a Chrome Extension

I'm trying to make a Chrome Extension which scrapes some details from Pull Requests on Github using the Fetch API, and then displays them elsewhere. I'm running into some problems when I try to use this with a non-public repository on Github. I believe this is related to CSRF protection, and the rules that govern Chrome extensions having access to session cookies.
I have the following in my extension's manifest.json:
"content_scripts": [{
"matches": [
"*://github.com/*/*/pulls"
],
"js": ["script/underscore-1.8.3.min.js", "script/content.js"]
}],
"permissions": [
"tabs",
"activeTab",
"*://github.com/*",
"webNavigation"
]
But when I run the following from within my script/content.js:
fetch('/redacted/redacted/pull/4549', {credentials: 'same-origin'}).then((response) => {
return response.text();
}).then((text) => {
// do cool stuff
})
This produces a 404 response from Github. Inspecting this request with Chrome Inspector's network tab, I can see it is not sending my GitHub session header with the request.
If I make the very same request using the Javascript prompt in the Inspector, I can see a 200 response, and I can see that it is sending my session cookies.
My understanding was that specifying the Github domain in my manifest.json would mean my extension would have access to my session data in my content scripts, is this not correct? What should I be doing to make a valid request to this protected content?
According to Chrome blog, to include cookies you need credentials: 'include' instead of credentials: 'same-origin'.
Specifying github in the permissions only gives access to the host, its there to limit damage if the extension/app is compromised by malware (source).
Its not indicated in the content script documentation that session data can be retrieved in content scripts, just their DOMs. I think it would be better if you use and incorporate the official Github API in the chrome extension project you're creating.

chrome.tabs.executeScript not working?

I am trying to learn to use the chrome.tabs.executeScript commend. I've created a simple extension with a browser action. My background.html file currently looks like this:
<html>
<script>
chrome.browserAction.onClicked.addListener(function(tab) {
chrome.tabs.executeScript(null,{code:"document.body.bgColor='red'"});
chrome.tabs.executeScript(null, {file: "content_script.js"});
});
</script>
</html>
The "content_script.js" file contains document.body.bgColor='red'.
When pushing the browser action's button nothing happens. Obviously I'm missing something very basic.
I've checked with console.log that indeed control reaches the chrome.tabs.executeScript calls when the browser action is pressed. Otherwise I'm not sure how to even check if my content script's code is run (it seems not; console.log I put in the content script has no effect, but maybe it shouldn't have one even if the script is run successfully).
Make sure you have domain and tab permissions in the manifest:
"permissions": [
"tabs", "http://*/*", "https://*/*"
]
Then to change body color try:
chrome.tabs.executeScript(null,{code:"document.body.style.backgroundColor='red'"});
Also keep in mind that content scripts are not injected into any chrome:// or extension gallery pages.
For those of you still having issues, you need to make sure to reload the extension's permissions in Chrome.
Go to chrome://extensions , scroll to your extension, and click on "reload". Make sure that your permissions have been updated by clicking on the permissions link right next to your extension.
You actually don't need and don't want the 'tabs' permission for executeScript.
"permissions": [
"http://*/*",
"https://*/*"
]
Should be enough.
It's not recommended to use http://*/* and https://*/*. From the Google documentation:
To inject a programmatic content script, provide the activeTab permission in the manifest. This grants secure access to the active site's host and temporary access to the tabs permission, enabling the content script to run on the current active tab without specifying cross-origin permissions.
Instead, (as suggested in the page) just use activeTab permission.
Remark: more explanation for the security issue
Without activeTab, this extension would need to request full, persistent access to every web site, just so that it could do its work if it happened to be called upon by the user. This is a lot of power to entrust to such a simple extension. And if the extension is ever compromised, the attacker gets access to everything the extension had.
In contrast, an extension with the activeTab permission only obtains access to a tab in response to an explicit user gesture. If the extension is compromised the attacker would need to wait for the user to invoke the extension before obtaining access. And that access only lasts until the tab is navigated or is closed.
(emphasis mine)
In the example code posted by the OP, activeTab is sufficient.
However, if the extension is more complex and needs to work "automatically" (i.e. without the user clicking the button); then this method will not work and additional permission is required.
Most of the answers above seems to be working fine for manifest version 2 but when it comes manifest-3 their seems to be some workaround to make the content-script load in the latest manifest 3.We need to use the following steps to execute content script in manifest 3
First adding permission "scripting" in manifest
"permissions": [
"storage",
"tabs",
"activeTab",
"scripting"
]
Once the scripting perimission is provided, we can use the scripting api like below
In background.js,
chrome.tabs.query({}, (tabList) => {
if (!tabList.length) return;
tabList.forEach((tab) => {
chrome.scripting.executeScript(
{
files: ['contentScript.js'],
target: {
tabId: tab.id,
allFrames: true
}
}
);
});
});
In the above code we are executing the contentScript for all the available tabs in tab browser.

Resources