In Chrome extensions, you cannot access or modify content from protocols other than file:, http:, ftp: and chrome-extension: (data:, blob: and filesystem: when the page created the resource themselves).
I considered four approaches to solve the problem:
- Bind a
beforeload event to the document, and change the URL when it matches about:blank.
Does not work: The CSP is activated before this event is fired.
- Bind a
DOMNodeInserted event to the document, and check for about:blank iframes.
Does not work: The CSP is activated before this event is fired.
- Use the
webRequest API to intercept the request.
Does not work: The strict match patterns do not allow the about: protocol.
- Change the
src property before inserting the IFRAME in the document:
- Either manually (best option), or
- Modify
document.createElement for IFrames, or
- Modify the
appendChild, insertBefore and replaceChild methods for Iframes.
For all methods, you have to create a dummy page, say blank.html within your extension, and allow access via web_accessible_resources.
Manifest file example (last four lines are important):
{
"name": "Name",
"version": "1.0",
"background": {"scripts": ["aboutblank.js"]},
"manifest_version": 2,
"content_security_policy": "default-src 'self'",
"web_accessible_resources": ["blank.html"]
}
aboutblank.js
var BLANK_PAGE = chrome.extension.getURL("blank.html");
(function(BLANK_PAGE, createElement, appendChild, insertBefore, replaceChild) {
HTMLDocument.prototype.createElement = function(str) {
var elem = createElement.call(this, str);
if (str.toUpperCase() == 'IFRAME') {
elem.src = BLANK_PAGE;
}
return elem;
};
Element.prototype.appendChild = function(newChild) {
iframe_check(newChild);
return appendChild.call(this, newChild);
};
Element.prototype.insertBefore = function(newChild, refChild) {
iframe_check(newChild);
return insertBefore.call(this, newChild, refChild);
};
Element.prototype.replaceChild = function(newChild, refChild) {
iframe_check(newChild);
return replaceChild.call(this, newChild, refChild);
};
function iframe_check(elem) {
if (elem instanceof HTMLIFrameElement && (elem.src == '' || elem.src.slice(0,11) == 'about:blank')) {
elem.src = BLANK_PAGE;
}
}
})(BLANK_PAGE,
HTMLDocument.prototype.createElement,
Element.prototype.appendChild,
Element.prototype.insertBefore,
Element.prototype.replaceChild);
Note: Option 1 is recommended over modifying these prototype methods. Also, the prototype method does not work for <iframes> injected using .innerHTML.