Prebid core: do not use `document.write` for rendering HTML
Type of change
- [x] Refactoring (no functional changes, no api changes)
Description of change
Replace core's usage of document.write with Element.innerHTML, with some additional logic to run scripts.
According to:
https://www.w3.org/TR/2008/WD-html5-20080610/dom.html#innerhtml0 https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML
'script' is the only major difference called out between document.write and innerHTML, with the rest being about state of the browser's internal parsers - which should hopefully not matter for us.
Other information
Closes https://github.com/prebid/Prebid.js/issues/8337
This pull request introduces 1 alert and fixes 1 when merging 232c5168b657f89ee702e57b157f9426c47b9709 into 79569f41bc626e5173ddd6b2a5cc00fdecdbcffc - view on LGTM.com
new alerts:
- 1 for Client-side cross-site scripting
fixed alerts:
- 1 for Client-side cross-site scripting
As it turns out from the test failures, it's more complicated than even the sync/async problem. I don't think this approach will work - but maybe someone has a better idea. We could try to pull in postscribe, but I'm not sure it's worth it.
In Firefox, newly created iframes behave like this:
const iframe = document.createElement('iframe');
document.body.appendChild(iframe);
const doc = iframe.contentDocument;
doc.body.appendChild(...) // does not work as expected, because:
iframe.contentWindow.addEventListener('DOMContentLoaded', function() {
doc === iframe.contentDocument // this is false in Firefox
doc.defaultView.document === iframe.contentDocument // but this, somehow, is true
})
I spent some time to try and code that in this PR, but I am running into other problems - I think because scripts do not run at the expected time.
Should core import postscribe?
As it turns out from the test failures, it's more complicated than even the sync/async problem. I don't think this approach will work - but maybe someone has a better idea. We could try to pull in postscribe, but I'm not sure it's worth it.
In Firefox, newly created iframes behave like this:
const iframe = document.createElement('iframe'); document.body.appendChild(iframe); const doc = iframe.contentDocument; doc.body.appendChild(...) // does not work as expected, because: iframe.contentWindow.addEventListener('DOMContentLoaded', function() { doc === iframe.contentDocument // this is false in Firefox doc.defaultView.document === iframe.contentDocument // but this, somehow, is true })I spent some time to try and code that in this PR, but I am running into other problems - I think because scripts do not run at the expected time.
Hello, couldn’t you use the srcdoc attribute of the iframe (srcdoc=“html code”) in order to apply the htmlcontent accordingly? It seems that low effort is needed and you could combine the src=“javascript:false” to avoid the default iframe and DOM behavior. Am I missing something? CC: @dgirardi @mkendall07 @patmmccann https://developer.mozilla.org/en-US/docs/Web/API/HTMLIFrameElement/srcdoc
@nikpil93 I think that would work, but in general we do not "own" the iframe, our API asks for a document object to write to and the iframe around it is (sometimes) created outside of our control. It may be worth changing the API in a major release though.
If the iframe is created by GPT we may need to drop another iframe within it for that approach, not sure if that would cause problems.