See also the warning at the end of this answer!
manifest.json for Chrome 96 and newer,
doesn't show a separate permission for "Block page content" during installation
"minimum_chrome_version": "96",
"permissions": ["declarativeNetRequestWithHostAccess"],
"host_permissions": ["*://*.example.com/"],
"background": {"service_worker": "bg.js"},
bg.js for Chrome 101 and newer using initiatorDomains
and requestDomains
(don't forget to add "minimum_chrome_version": "101"
in manifest.json)
const iframeHosts = [
'example.com',
];
chrome.runtime.onInstalled.addListener(() => {
const RULE = {
id: 1,
condition: {
initiatorDomains: [chrome.runtime.id],
requestDomains: iframeHosts,
resourceTypes: ['sub_frame'],
},
action: {
type: 'modifyHeaders',
responseHeaders: [
{header: 'X-Frame-Options', operation: 'remove'},
{header: 'Frame-Options', operation: 'remove'},
// Uncomment the following line to suppress `frame-ancestors` error
// {header: 'Content-Security-Policy', operation: 'remove'},
],
},
};
chrome.declarativeNetRequest.updateDynamicRules({
removeRuleIds: [RULE.id],
addRules: [RULE],
});
});
Old Chrome 84-100
Use the following instead, if your extension should be compatible with these old versions.
manifest.json for Chrome 84 and newer,
shows a separate permission for "Block page content" during installation
"permissions": ["declarativeNetRequest"],
"host_permissions": ["*://*.example.com/"],
"background": {"service_worker": "bg.js"},
bg.js for Chrome 84 and newer using the now deprecated domains
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'},
// Uncomment the following line to suppress `frame-ancestors` error
// {header: 'Content-Security-Policy', operation: 'remove'},
],
},
})),
});
});
Warning: beware of site's service worker
You may have to remove the service worker of the site(s) before adding the iframe or before opening the extension page because many modern sites use the service worker to create the page without making a network request thus ignoring our header-stripping rule.
Add "browsingData"
to "permissions"
in manifest.json
Clear the SW:
function removeSW(url) {
return chrome.browsingData.remove({
origins: [new URL(url).origin],
}, {
serviceWorkers: true,
});
}
// If you add an iframe element in DOM:
async function addIframe(url, parent = document.body) {
await removeSW(url);
const el = document.createElement('iframe');
parent.appendChild(el);
el.src = url;
return el;
}
// If you open an extension page with an <iframe>
element in its HTML:
async function openPage(url) {
await removeSW('https://example.com/');
return chrome.tabs.create({url});
}
X-Frame-Options
. In javascript, no error is thrown and no events are triggered when a page load is blocked byX-Frame-Options
. – Schnurr