Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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!

like image 915
Ian McIntyre Silber Avatar asked Mar 20 '13 19:03

Ian McIntyre Silber


People also ask

How do I ignore X-Frame-options?

If you want to load a other website into an iFrame and you get the Display forbidden by X-Frame-Options” error then you can actually overcome this by creating a server side proxy script. This by passes the block, because it is just a GET request that might as wel have been a ordinary browser page visit.

Does Chrome support X-Frame-options allow From?

Chrome does not support the ALLOW-FROM directive in X-Frame-Options. So if we are going to do anything involving other domains, we need something similar. We can stitch together a patchwork configuration involving both headers, which does something more than just allow same-origin framing.

What is X-Frame-Options deny?

X-Frame-Options:DENY is a header that forbids a page from being displayed in a frame. If your server is configured to send this heading, your sign-on screen will not be allowed to load within the embed codes provided by Credo, which use the iframe HTML element.

What is blocked by X-Frame-Options policy?

You can't set X-Frame-Options on the iframe. That is a response header set by the domain from which you are requesting the resource . They have set the header to SAMEORIGIN in this case, which means that they have disallowed loading of the resource in an iframe outside of their domain.


2 Answers

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.

like image 69
Rob W Avatar answered Sep 19 '22 14:09

Rob W


ManifestV3 example using declarativeNetRequest

Let's use the new declarativeNetRequest API to strip the header only when the iframe is embedded in pages of our extension.

manifest.json:

  "permissions": ["declarativeNetRequest"],   "host_permissions": ["*://*.example.com/"],   "background": {"service_worker": "bg.js"}, 

The declarativeNetRequest permission adds an entry in the installation dialog that your extension can "Block page content" so to avoid it you can use declarativeNetRequestWithHostAccess:

manifest.json for Chrome 96 and newer, no installation warning:

  "minimum_chrome_version": "96",   "permissions": ["declarativeNetRequestWithHostAccess"],   "host_permissions": ["*://*.example.com/"],   "background": {"service_worker": "bg.js"}, 

bg.js:

const iframeHosts = [   'example.com', ]; chrome.runtime.onInstalled.addListener(() => {   chrome.declarativeNetRequest.updateDynamicRules({     removeRuleIds: iframeHosts.map((h, i) => i + 1),     addRules: iframeHosts.map((h, i) => ({       id: i + 1,       condition: {         domains: [chrome.runtime.id],         urlFilter: `||${h}/`,         resourceTypes: ['sub_frame'],       },       action: {         type: 'modifyHeaders',         responseHeaders: [           {header: 'X-Frame-Options', operation: 'remove'},           {header: 'Frame-Options', operation: 'remove'},         ],       },     })),   }); }); 
like image 28
wOxxOm Avatar answered Sep 20 '22 14:09

wOxxOm