Search code examples
javascriptiframegoogle-chrome-extensionx-frame-options

Getting around X-Frame-Options DENY in a Chrome extension?


I'm the author of Intab, a Chrome extension that lets you view a link inline as opposed to a new tab. There's not much fancy stuff going on behind the scenes, it's just an iframe that loads the URL the user clicked on.

It works great except for sites that set the X-Frame-Options header to DENY or SAMEORIGIN. Some really big sites like Google and Facebook both use it which makes for a slightly janky experience.

Is there any way to get around this? Since I'm using a Chrome extension, is there any browser level stuff I can access that might help? Looking for any ideas or help!


Solution

  • This answer is for ManifestV2 and policy-installed MV3 extensions.
    For normal ManifestV3 extensions see the other answer(s).

    Chrome offers the webRequest API to intercept and modify HTTP requests. You can remove the X-Frame-Options header to allow inlining pages within an iframe.

    chrome.webRequest.onHeadersReceived.addListener(
        function(info) {
            var headers = info.responseHeaders;
            for (var i=headers.length-1; i>=0; --i) {
                var header = headers[i].name.toLowerCase();
                if (header == 'x-frame-options' || header == 'frame-options') {
                    headers.splice(i, 1); // Remove header
                }
            }
            return {responseHeaders: headers};
        }, {
            urls: [
                '*://*/*', // Pattern to match all http(s) pages
                // '*://*.example.org/*', // Pattern to match one http(s) site
            ], 
            types: [ 'sub_frame' ]
        }, [
            'blocking',
            'responseHeaders',
            // Modern Chrome needs 'extraHeaders' to see and change this header,
            // so the following code evaluates to 'extraHeaders' only in modern Chrome.
            chrome.webRequest.OnHeadersReceivedOptions.EXTRA_HEADERS,
        ].filter(Boolean)
    );
    

    In the manifest, you need to specify the webRequest and webRequestBlocking permissions, plus the URLs patterns you're intending to intercept i.e. "*://*/*" or "*://www.example.org/*" for the example above.