3

I'm trying to detect if an extension is installed on a user's browser.

I tried this:

var detect = function(base, if_installed, if_not_installed) {
    var s = document.createElement('script');
    s.onerror = if_not_installed;
    s.onload = if_installed;
    document.body.appendChild(s);
    s.src = base + '/manifest.json';
}
detect('chrome-extension://' + addon_id_youre_after, function() {alert('boom!');});

If the browser has the extension installed I will get an error like:

Resources must be listed in the web_accessible_resources manifest key in order to be loaded by pages outside the extension

GET chrome-extension://invalid net::ERR_FAILED

If not, I will get a different error.

GET chrome-extension://addon_id_youre_after/manifest.json net::ERR_FAILED

Here is an image of the errors I am getting: The errors I am getting from the fiddle

I tried to catch the errors (fiddle)

try {
  var s = document.createElement('script');
    //s.onerror = window.setTimeout(function() {throw new Error()}, 0);
    s.onload = function(){alert("installed")}; 
    document.body.appendChild(s);
    s.src = 'chrome-extension://gcbommkclmclpchllfjekcdonpmejbdp/manifest.json';
} catch (e) {
  debugger;
  alert(e);
}

window.onerror = function (errorMsg, url, lineNumber, column, errorObj) {
    alert('Error: ' + errorMsg + ' Script: ' + url + ' Line: ' + lineNumber
    + ' Column: ' + column + ' StackTrace: ' +  errorObj);
}

So far I am not able to catch the errors..
Any help will be appreciated

Xan
  • 74,770
  • 16
  • 179
  • 206
Offir
  • 3,252
  • 3
  • 41
  • 73
  • Ah, this is an interesting idea. I see existing answers that utilize XMLHttpRequest and check the response for error. – wOxxOm Nov 01 '16 at 09:29
  • @wOxxOm , That's what I am trying to do, but I can't catch the error from some reason. look at the updated question, I added an image. – Offir Nov 01 '16 at 09:31
  • @wOxxOm I don't think it will work because chrome-extension: doesn't work like that, it's like inner request from the browser. – Offir Nov 01 '16 at 09:34
  • See my comment on your original question. This method does not work anymore, and I linked a question that explains all the possibilities. – Xan Nov 01 '16 at 09:43
  • @Xan All answers to the questions you mentioned in my original question(which is different) are basically saying NO, This is not possible. So why not keeping this question open and let other people that are not you suggest solutions, Maybe Try to help me catch the exception that rises from the fiddle I have added. – Offir Nov 01 '16 at 09:55
  • Okay, now I see that this question is suitably different indeed (how to catch this specific error). I'll undupe and edit the question a bit to let it stand out. – Xan Nov 01 '16 at 09:57
  • Maybe the title should be , "How to detect extension on a browser based on exceptions?" – Offir Nov 01 '16 at 09:59
  • No, that title would be indeed a duplicate of what I closed [your first question](https://stackoverflow.com/questions/40345467/in-a-webpage-how-can-i-detect-that-a-particular-extension-is-loaded-in-a-browse) with. It doesn't matter if that doesn't have the answer you wish to have: it's an already existing question on the topic. Offer a bounty saying answers are outdated, if you wish. This question, however, is about catching those specific errors. This is not a dupe, and answerable. – Xan Nov 01 '16 at 10:03
  • Here you go, an answer to this question with an addendum on why this doesn't work (spoiler: because Google doesn't want it to). – Xan Nov 01 '16 at 10:38
  • there are other non generic ways to detect extensions. example if such extension modifies the dom, you could detect it, or if the extension opens windows of its resources, the tabs permission can let you detect such urls being opened. last one requires waiting for the user to open such tab thou, and first one requires the extension to be content script and user to visit page. – Zig Mandel Nov 01 '16 at 14:55
  • @ZigMandel although I didn't mentioned it in the question I was looking for a generic way to do so, cause I want to check an array of extension by their ids. – Offir Nov 01 '16 at 15:28

2 Answers2

3

The first error is informative from Chrome, injected directly into the console and not catchable by you (as you noticed).

The GET errors are from the network stack. Chrome denies load in either case and simulates a network error - which you can catch with onerror handler on the element itself, but not in the window.onerror hander. Quote, emphasis mine:

When a resource (such as an <img> or <script>) fails to load, an error event using interface Event is fired at the element, that initiated the load, and the onerror() handler on the element is invoked. These error events do not bubble up to window, but (at least in Firefox) can be handled with a single capturing window.addEventListener.

Here's an example that will, at least, detect the network error. Note that, again, you can't catch them, as in prevent it from showing in the console. It was a source of an embarrasing problem when Google Cast extension (that was exposing a resource) was using it as a detection method.

s.onload = function(){alert("installed")}; 
s.error = function(){alert("I still don't know")};

Notice that you can't distinguish between the two. Internally, Chrome redirects one of the requests to chrome-extension://invalid, but such redirects are transparent to your code: be it loading a resource (like you do) or using XHR. Even the new Fetch API, that's supposed to give more control over redirects, can't help since it's not a HTTP redirect. All it gets is an uninformative network error.

As such, you can't detect whether the extension is not installed or installed, but does not expose the resource.


Please understand that this is intentional. The method you refer to used to work - you could fetch any resource known by name. But it was a method of fingerprint browsers - something that Google is explicitly calling "malicious" and wants to prevent.

As a result, web_accessible_resources model was introduced in Chrome 18 (all the way back in Aug 2012) to shield extensions from sniffing - requiring to explicitly declare resources that are exposed. Quote, emphasis mine:

Prior to manifest version 2 all resources within an extension could be accessed from any page on the web. This allowed a malicious website to fingerprint the extensions that a user has installed or exploit vulnerabilities (for example XSS bugs) within installed extensions. Limiting availability to only resources which are explicitly intended to be web accessible serves to both minimize the available attack surface and protect the privacy of users.

With Google actively fighting fingerprinting, only cooperating extensions can be reliably detected. There may be extension-specific hacks - such as specific DOM changes, request interceptions or exposed resources you can fetch - but there is no general method, and extension may change their "visible signature" at any time. I explained it in this question: Javascript check if user has a third party chrome extension installed, but I hope you can see the reason for this better.

To sum this up, if you indeed were to find a general method that exposed arbitrary extensions to fingerprinting, this would be considered malicious and a privacy bug in Chrome.

Xan
  • 74,770
  • 16
  • 179
  • 206
-1

Have your Chrome extension look for a specific DIV or other element on your page, with a very specific ID.

For example:-

<div id="ExtensionCheck_JamesEggersAwesomeExtension"></div>