google chrome extension rejected http request - javascript

I've prepared chrome extension that was rejected to be published because of some issues (they haven't specified what is wrong exactly). Below message i recieved from them about rejection:
Your item "[name of extension]" [here some kind of id] is
being taken down as it currently violates the section of the Developer
Program Policy relating to Malicious Products as its obfuscating a
part of code. Per our policies, where possible, make as much of your
code visible in the package as you can. If some of your app's logic is
hidden and it appears to be suspicious, we may remove it.
To have your item reinstated, please make any necessary changes to
ensure:
All of the files and code are included in the item’s package.
All code inside the package is human readable (no obfuscated or minified code).
Avoid requesting or executing remotely hosted code (including by referencing remote javascript files or executing code obtained by XHR requests).
Most probably they don't like this part of my code
$.get('http://mydomain/catalogue/message.php?date=' + today, function() {})
.done(function(responseMessage) {
chrome.notifications.create(
'reminder'
,{type: 'basic'
,title: responseTopic
,iconUrl: "small.jpg"
,message: responseMessage}
,function(notificationId) {});
});
This request suppose to answer with a text message to notify the user. Is this a threat? Can javascript be injected this way? If yes, can I strip it somehow?

Related

Webpack code splitting: ChunkLoadError - Loading chunk X failed, but the chunk exists

I've integrated Sentry with my website a few days ago and I noticed that sometimes users receive this error in their console:
ChunkLoadError: Loading chunk <CHUNK_NAME> failed.
(error: <WEBSITE_PATH>/<CHUNK_NAME>-<CHUNK_HASH>.js)
So I investigated the issue around the web and discovered some similar cases, but related to missing chunks caused by release updates during a session or caching issues.
The main difference between these cases and mine is that the failed chunks are actually reachable from the browser, so the loading error does not depend on the after-release refresh of the chunk hashes but (I guess), from some network related issue.
This assumption is reinforced by this stat: around 90% of the devices involved are mobile.
Finally, I come to the question: Should I manage the issue in some way (e. g. retrying the chunk loading if failed) or it's better to simply ignore it and let the user refresh manually?
2021.09.28 edit:
A month later, the issue is still occurring but I have not received any report from users, also I'm constantly recording user sessions with Hotjar but nothing relevant has been noticed so far.
I recently had a chat with Sentry support that helped me excluding the network related hypotesis:
Our React SDK does not have offline cache by default, when an error is captured it will be sent at that point. If the app is not able to connect to Sentry to send the event, it will be discarded and the SDK will no try to send it again.
Rodolfo from Sentry
I can confirm that the issue is quite unusual, I share with you another interesting stat: the user affected since the first occurrence are 882 out of 332.227 unique visitors (~0,26%), but I noticed that the 90% of the occurrences are from iOS (not generic mobile devices as I noticed a month ago), so if I calculate the same proportion with iOS users (794 (90% of 882) out of 128.444) we are near to a 0,62%. Still small but definitely more relevant on iOS.
This is most likely happening because the browser is caching your app's main HTML file, like index.html which serves the webpack bundles and manifest.
First I would ensure your web server is sending the correct HTTP response headers to not cache the app's index.html file (let's assume it is called that). If you are using NGINX, you can set the appropriate headers like this:
location ~* ^.+.html$ {
add_header Cache-Control "no-store max-age=0";
}
This file should be relatively small in size for a SPA, so it is ok to not cache this as long as you are caching all of the other assets the app needs like the JS and CSS, etc. You should be using content hashes on your JS bundles to support cache busting on those. With this in place visits to your site should always include the latest version of index.html with the latest assets including the latest webpack manifest which records the chunk names.
If you want to handle the Chunk Load Errors you could set up something like this:
import { ErrorBoundary } from '#sentry/react'
const App = (children) => {
<ErrorBoundary
fallback={({ error, resetError }) => {
if (/ChunkLoadError/.test(error.name)) {
// If this happens during a release you can show a new version alert
return <NewVersionAlert />
// If you are certain the chunk is on your web server or CDN
// You can try reloading the page, but be careful of recursion
// In case the chunk really is not available
if (!localStorage.getItem('chunkErrorPageReloaded')) {
localStorage.setItem('chunkErrorPageReloaded', true)
window.location.reload()
}
}
return <ExceptionRedirect resetError={resetError} />
}}>
{children}
</ErrorBoundary>
}
If you do decide to reload the page I would present a message to the user beforehand.
The chunk is reachable doesn't mean the user's browser can parse it. For example, if the user's browser is old. But the chunk contains new syntax.
Webpack loads the chunk by jsonp. It insert <script> tag into <head>. If the js chunk file is downloaded but cannot parsed. A ChunkLoadError will be throw.
You can reproduce it by following these steps. Write an optional chain and don't compile it. Ensure it output to a chunk.
const obj = {};
obj.sub ??= {};
Open your app by chrome 79 or safari 13.0. The full error message looks like this:
SyntaxError: Unexpected token '?' // 13.js:2
MAX RELOADS REACHED // chunk-load-handler.js:24
ChunkLoadError: Loading chunk 13 failed. // trackConsoleError.js:25
(missing: http://example.com/13.js)

Modify <meta> tag with JS (chrome extension) on response receiving

I have a Chrome extension that adds a panel to the page in the floating iframe (on extension button click). There's certain JS code that is downloaded from 3rd party host and needs to be executed on that page. Obviously there's XSS issue and extension needs to comply with content security policies for that page.
Previously I had to deal with CSP directives that are passed via request headers, and was able to override those via setting a hook in chrome.webRequest.onHeadersReceived. There I was adding my host URL to content-security-policy headers. It worked. Headers were replaced, new directives applied to the page, all good.
Now I discovered websites that set the CSP directives via <meta> tag, they don't use request headers. For example, app pages in iTunes https://itunes.apple.com/us/app/olympics/id808794344?mt=8 have such. There is also an additional meta tag with name web-experience-app/config/environment (?) that somewhat duplicates the values that are set in content of tag with http-equiv="Content-Security-Policy".
This time I am trying to add my host name into meta tag inside chrome.webNavigation.onCommitted or onCompleted events listeners (JS vanilla via chrome.tabs.executeScript). I also experimented with running the same code from the webrequest's onCompleted listener (at the last step of lifecycle according to https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/webRequest).
When I inspect the page after its load - I see the meta tags have changed. But when I click on my extension to start loading iframe and execute JS - console prints the following errors:
Refused to frame 'https://myhost.com' because it violates the following Content Security Policy directive: "frame-src 'self' *.apple.com itmss: itms-appss: itms-bookss: itms-itunesus: itms-messagess: itms-podcasts: itms-watchs: macappstores: musics: apple-musics:".
I.e. my tag update was not effective.
I have several questions: first, do I do it right? Am I doing the update at the proper event? When is the data content from meta tags being read in the page lifecycle? Will it be auto-applied after tag content change?
As of March 2018 Chromium doesn't allow to modify the responseBody of the request. https://bugs.chromium.org/p/chromium/issues/detail?id=487422#c29
"WebRequest API: allow extensions to read response body" is a ticket from 2015. It is not on a path of getting to be resolved and needs some work/help.
--
Firefox has the webRequest filter implementation that allows to modify the response body before the page's meta directives are applied.
https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/webRequest/filterResponseData
BUT, my problem is focused on fixing the Chrome extension. Maybe Chrome picks this up one day.
--
In general, the Chrome's extension building framework seems like not a reliable path of building a long term living software; with browser vendors changing the rules frequently, reacting to newly discovered threats, having no up-to-date supported cross-browser standard.
--
In my case, the possible way around this issue can be to throw all the JS code into the extension's source base. Such that there's no 3-rd party to connect to fetch and execute the JS (and conflict with/violate the CSP rules). Haven't explored this yet, as I expected to reuse the code & interactive components I am using in my main browser application.
I've been interested in the same things and here are a few aspects that perhaps could help:
chrome.debugger extension API with Fetch (or Network) domain can be used to modify responseBody: https://chromedevtools.github.io/devtools-protocol/tot/Fetch/
This is an example implementation: https://github.com/mr-yt12/Debugger-API-Fetch-example-Chrome-Extension
However, I'm facing a problem of Fetch.requestPaused not firing on the first page load: Chrome Extension Debugger API, Fetch domain attaches/enables too late for the response body to be intercepted
And I haven't found a solution to this yet, besides first redirecting the request to 'http://google.com/gen_204' and then updating the tab. But this creates flicker and also I'm not sure if it's possible to redirect the request like this with manifest v3.
When using debugger API, Chrome shows a warning at the top, which changes the page's size and doesn't go away (perhaps it goes away 5 seconds after the debugger is detached and also if the user clicks "cancel"). This means that it's mostly only good for personal use or when distributing as a developer mode extension. Using --silent-debugger-extension-api flag with Chrome disables this warning.
I've tried injecting my script at document_start (when the meta tag is not yet created). Then I used mutationObserver (also tried other methods) to wait for the meta tag, to modify it before it's applied or fully created. Somehow it succeeded once or a few times, but could be a coincidence or a wrong interpretation of results. Perhaps it's worth experimenting with it.
Another idea (but I think I didn't make it work, but perhaps it's possible) is to use window.stop() at document_start and then rewrite the html content programmatically. This needs more researching.
It seems that meta tag CSP is applied once the meta tag is created (or while it's being created), and then there is no way to cancel what's been applied. It should be researched more on how to prevent it from applying or modifying it before it's fully created or applied.

Is there an alternative to preprocessorScript for Chrome DevTools extensions?

I want to create a custom profiler for Javascript as a Chrome DevTools Extension. To do so, I'd have to instrument all Javascript code of a website (parse to AST, inject hooks, generate new source). This should've been easily possible using chrome.devtools.inspectedWindow.reload() and its parameter preprocessorScript described here: https://developer.chrome.com/extensions/devtools_inspectedWindow.
Unfortunately, this feature has been removed (https://bugs.chromium.org/p/chromium/issues/detail?id=438626) because nobody was using it.
Do you know of any other way I could achieve the same thing with a Chrome Extension? Is there any other way I can replace an incoming Javascript source with a changed version? This question is very specific to Chrome Extensions (and maybe extensions to other browsers), I'm asking this as a last resort before going a different route (e.g. dedicated app).
Use the Chrome Debugging Protocol.
First, use DOMDebugger.setInstrumentationBreakpoint with eventName: "scriptFirstStatement" as a parameter to add a break-point to the first statement of each script.
Second, in the Debugger Domain, there is an event called scriptParsed. Listen to it and if called, use Debugger.setScriptSource to change the source.
Finally, call Debugger.resume each time after you edited a source file with setScriptSource.
Example in semi-pseudo-code:
// Prevent code being executed
cdp.sendCommand("DOMDebugger.setInstrumentationBreakpoint", {
eventName: "scriptFirstStatement"
});
// Enable Debugger domain to receive its events
cdp.sendCommand("Debugger.enable");
cdp.addListener("message", (event, method, params) => {
// Script is ready to be edited
if (method === "Debugger.scriptParsed") {
cdp.sendCommand("Debugger.setScriptSource", {
scriptId: params.scriptId,
scriptSource: `console.log("edited script ${params.url}");`
}, (err, msg) => {
// After editing, resume code execution.
cdg.sendCommand("Debugger.resume");
});
}
});
The implementation above is not ideal. It should probably listen to the breakpoint event, get to the script using the associated event data, edit the script and then resume. Listening to scriptParsed and then resuming the debugger are two things that shouldn't be together, it could create problems. It makes for a simpler example, though.
On HTTP you can use the chrome.webRequest API to redirect requests for JS code to data URLs containing the processed JavaScript code.
However, this won't work for inline script tags. It also won't work on HTTPS, since the data URLs are considered unsafe. And data URLs are can't be longer than 2MB in Chrome, so you won't be able to redirect to large JS files.
If the exact order of execution of each script isn't important you could cancel the script requests and then later send a message with the script content to the page. This would make it work on HTTPS.
To address both issues you could redirect the HTML page itself to a data URL, in order to gain more control. That has a few negative consequences though:
Can't reload page because URL is fixed to data URL
Need to add or update <base> tag to make sure stylesheet/image URLs go to the correct URL
Breaks ajax requests that require cookies/authentication (not sure if this can be fixed)
No support for localStorage on data URLs
Not sure if this works: in order to fix #1 and #4 you could consider setting up an HTML page within your Chrome extension and then using that as the base page instead of a data URL.
Another idea that may or may not work: Use chrome.debugger to modify the source code.

Determine which advertisement made a request to /eyeblaster/addineyev2.html

I have a large website that is using two large online advertisement "Remnant" providers. These providers are such that they start and stop ad campaigns on a regular basis that run on our website.
One of the ads coming from one of the providers is incorrectly making a request to:
/eyeblaster/addineyev2.html
I have determined that the file being requested is used by some websites when the ads on the website are served via iframes. This file in theory would circumvent the cross domain restrictions so that the ad provider could resize the iframe using javascript within the iframe.
I determined this use of the file by stumbling upon this support document:
http://support.google.com/dfp_premium/bin/answer.py?hl=en&answer=1085693
My problem is that our websites do not use iframes to deliver advertisements, so the requests going to the "/eyeblaster/addineyev2.html" URI results in a 404 error, and is unnecessary. Because the error is coming from a large vendor-provided CMS the error renders with our Google Analytics tracking code on it. This has the result of inflating our apparent pageviews.
The pageview inflation can be very severe, because the 404 error page also contains ads. That 404 page could also load the faulty ad, resulting in a recursive loop of ads loading the exact same "/eyeblaster/addineyev2.html" 404 page.
I have thus far been unable to witness an ad making a direct request to this url via Firebug or similar developer tools. Yet, the traffic to this non-existent page is gigantic so the offending ad is certainly still in the mix. The problem is that I cannot figure out which ad is broken, so I can't tell our remnant providers to remove it. Both vendors are feigning ignorance of the issue.
I cannot remove the Google tracking code on the 404 error page, but I can add additional JavaScript to the page.
Is there any way that I could identify the ad causing a request to "/eyeblaster/addineyev2.html" by adding some javascript to the 404 error that results when trying to request that page inside an iframe?
Essentially almost a "frame buster" script that instead of busting the frame, gives information on the HTML nodes nearby the iframe element? I think it's mildly possible, but I'm not seeing a clear path at the moment.
Thanks!
To avoid that unwanted tracking you should place a dummy empty file on /eyeblaster/addineyev2.html, or, if you use nginx do something like
server {
...
location = /eyeblaster/addineyeV2.html { echo ""; }
}
or, better
server {
...
location = /eyeblaster/addineyeV2.html { return 404 "404 - page not found";}
}
If you don`t have static hosting and cannot configure a proxy server you can put a condition in your 404 page tracking via javascript
if (document.URL.indexOf('/eyeblaster/addineyeV2.html') == -1) {
doAnalyticsTracking();
}
I have found my own answer, and I'll share it here for the rare event another Web Developer is trying in vain to pinpoint an ad doing this same thing to them.
The offending digital ad was coming in with an iframe that was pointed toward "/eyeblaster/addineyev2.html" I used this knowledge, and coded the following javascript to gather information about the page that contained the iframe (ie the page with the ad on it).
if(top != self) {
$.post("/ad_diagnose/log.php", {
a: $('#ad-div-one', top.document).html(),
b: $('#ad-div-two', top.document).html(),
c: $('#ad-div-three', top.document).html(),
d: $('#ad-div-four', top.document).html(),
e: $('#ad-div-five', top.document).html(),
});
}
This JavaScript uses JQuery (which our CMS provider includes on every page anyway). It checks to see if the error page exists in an iframe (top != self), and then it grabs the raw html for every html element on the parent page that should contain an ad.
That data is wrapped into an object, and posted to a simple php script that would write a log of every value posted to it to a file.
In the end, I received a log file with a high likelihood that the offending ad code was within. I was able to do a quick grep on the file and discovered the ad with an iframe pointing toward "/eyeblaster/addineyev2.html"
I hope this helps someone else out there!
It looks like there are more publishers having this issue. I do too. Following Tals instructions I was able to log information when pointing an iframe to a 404-page on purpose, but wasn't able to catch this problem as it appears randomly and I can't check why the script is not catching it.
How about adding /eyeblaster/addineyev2.html and log from this file?
I was able to determine the owner of the script doing a simple web search. It is coming from http://www.mediamind.com/
But disabling "mediamind" in Google AdSense doesn't do the trick, so I asked their support to send me the file.
I am going to test the script and if 404-calls are getting lower. Maybe I will also use the script to check for the content being loaded and determine the exect ad url to shut it down.
Just thought I would share that this is happening over at our Ozzu website as well. I was first aware of the issue when some of our members were complaining, but I didn't look too deeply as I first thought it was an isolated instance.
Over the past month I have also noticed that my error log files on the server have been higher than normal pushing the /usr partition to around 82% of its usage. I didn't put two and two together until today as I finally started looking through the errors and it appears that this is not an isolated instance with this eyeblaster type ads. There are many thousands of users coming to our site and then getting redirected to a 404 page on our website because of this. Here is a sample of one of the errors in our log file, and it appears that numerous networks are using this eyeblaster software from Media Mind:
[Thu Dec 13 16:36:51 2012] [error] [client 123.123.123.123] File does not exist: /public_html/eyeblaster, referer: http://lax1.ib.adnxs.com/if?enc=AAAAAAAAAAAAAAAAAAAAAAAAAGC4Hvs_AAAAAAAAAAAAAAAAAAAAAMqchzp-qp9L_vlliXOoLV2gdMpQAAAAAEMUDABGAQAAQAEAAAIAAADXo0AA-FcCAAAAAQBVU0QAVVNEAKAAWAIAeAAAYk4AAgMCAQUAAIIA5BXJnQAAAAA.&cnd=%21QxtEWwidpzIQ18eCAhgAIPivCTAEOIDwBUABSMACUMOoMFgAYL4FaABwKngAgAH6AYgBAJABAZgBAaABAqgBALABALkBAAAAAAAAAADBAQAAAAAAAAAAyQEgEFk1j_LCP9kBAAAAAAAA8D_gAQA.&udj=uf%28%27a%27%2C+15986%2C+1355445408%29%3Buf%28%27c%27%2C+824221%2C+1355445408%29%3Buf%28%27r%27%2C+4236247%2C+1355445408%29%3B&ccd=%21mgWjMAidpzIQ18eCAhj4rwkgAQ..&vpid=18&referrer=http%3A%2F%2Fwww.ozzu.com%2F&dlo=1
[Thu Dec 13 16:36:56 2012] [error] [client 123.123.123.123] File does not exist: /public_html/eyeblaster
I have just contacted the Media Mind company as well to see if they have any further input. The errors in our logs are at least coming from a few ad servers such as:
lax1.ib.adnxs.com
showads.pubmatic.com
ad.yieldmanager.com
So it is my impression that numerous Media companies are using this Eye Blaster software. I looked more into what Eye Blaster supposedly does, and it is some sort of technology that syncs numerous ads on the page as if they are one big ad. For instance an animation will start in one ad and end in another. Anyway it must be popular as numerous ad companies seem to be using it and as such I would probably have to disabled alot of advertisers.
I think the best way to fix the problem would be to have Media Mind address it, but I am not sure.
Anyway just wanted to share my experience and that this problem seems to be affecting numerous websites.

Beginner Assistance - Where does this code belong?

I'm trying to develop a firefox extension that inserts additional HTTP header fields into outgoing HTTP requests (to interface with an apache extension i'm concurrently developing).
While I understand the individual components of an extension and understand the basic tutorials that are presented on the web, I'm finding it difficult going from the "Hello World" tutorial extensions, into developing a full blown extension.
The sample code I am wanting to adapt for my purposes is presented at the bottom of Setting HTTP request headers.
I am wondering, where in the extension hierarchy should this code be placed and how is such code called/constructed/activated, will it run automatically when the extension is initialised?
Thanks in advance.
For a basic extension, you would place your code in the chrome/content directory of the extension. You would hook this content into Firefox using an overlay. While overlays are usually xul content (buttons, etc) they can be anything. Including a script tag which would load fire off your Javascript code.
That code is an XPCOM component and goes into a components/<some name>.js file.
You should read up on XPCOM components if you want to dig it, but yes, .js files in components are loaded at startup. Such files contain registration code (starts at the var myModule = { line in that example), which tells Firefox whether the component defined in the file is available upon request or should it be instantiated automatically.
In that example you can see the component getting registered to be notified of the application's startup:
catMgr.addCategoryEntry("app-startup", this.myName, this.myProgID, true, true);
and when handling the app-startup notification it registers itself for the http-on-modify-request notification:
os.addObserver(this, "http-on-modify-request", false);

Categories