Cross origin framing in webextensions

Hello everyone.

I am porting a legacy extension to the new WebExt. The main problem with this extension is that it works loading webpages into iframes, but as far as I’ve read that’s not possible with some websites for security reasons. Indeed sometimes I get the “does not permit cross-origin framing” and the extension stop working there. The old extension created the iframes like this:

this.newIframe = function(URL) {

this.myIframe = this.getDocument().createElement("Myiframe");   
this.myIframe.setAttribute("id", "MyIframe" + indexIframes);       

this.myIframe.setAttribute("name", "MyIframe" + indexIframes);

}

Is there any way to make this work in WebExt or an alternative?

Thank you in advance.

Greetings.

How did that code ever produce an iframe element?

Anyway, (in Firefox) WebExtensions now get around framing restrictions made by the “host” page, but I think restrictions made by the (to be) “guest” page still apply.
AFAIK these restrictions are (only) expressed in the X-Frame-Options and Content-Security-Policy headers.
You could intercept them and whitelist the current host page. It would be quite a lot of work though. And a potential security risk if you get things wrong.

It may be easier that it sounds. All you need to do is register custom header handler:

browser.webRequest.onHeadersReceived.addListener(onFrameHeader, {urls: ['*://*/*'], types: ['sub_frame']}, ['blocking', 'responseHeaders']);

With the following implementation:

function onFrameHeader(info) {
  const headers = info.responseHeaders;
  for (let i = headers.length - 1; i >= 0; --i) {
    const header = headers[i].name.toLowerCase();
    if (header === 'x-frame-options' || header === 'frame-options' || header === 'content-security-policy') headers.splice(i, 1);
  }
  return {responseHeaders: headers};
}

Don’t forget to unregister the handler once you done!!!

It works for most of the pages, however there are some pages that uses JavaScript based protection that may be much harder to overcome.

While that way work, simply removing those security headers on all sub_frame requests (even if just for a time) is definitely:

a potential security risk if you get things wrong.

1 Like

Is there a better solution?

I don’t want to delete existing headers and rise security issues, I’d rather modify headers to allow extension resources to be loaded. Can someone more experienced help me do it?

I think extension resources should not be affected and blocked by any website header.

Well, if you only need to do this for a single URL(-prefix)/domain and all these documents are served with the same (relevant) headers, you can change exactly those headers in exactly the way required. That’s perfectly ok.

But that depends on the headers. In general it’s rather complex, so what’s the exact header you receive from the server?

I’m author of “I don’t care about cookies” extension and I need to somehow be able to access all iframes on all websites, so I get all possible combinations of headers.

So you don’t actually want to frame the pages yourself, but you want to access framed pages?

You don’t need to modify any headers for that, just inject content scripts with the { frameId, } or { allFrames, } option.

I already use allFrames. I don’t target with frameId because that can be too much on websites which constantly create new frames.

I tested a bit more and now I see that my problem is not here. It’s in the insertCSS which will not apply the code to frames if they are not already set when their parent is set. If you have a solution for that, I’ll be very thankfull (it’s a different topic, I can create a separate one if needed).

I don’t think I really understand what you are saying …

But this might be helpful: https://github.com/NiklasGollenstede/re-style/blob/master/background/web/index.js
It injects styles, with special handling for subframes (see the event listeners). Maybe that is your issue as well.