Prebid.js icon indicating copy to clipboard operation
Prebid.js copied to clipboard

Prebid core: do not use `document.write` for rendering HTML

Open dgirardi opened this issue 3 years ago • 3 comments

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

dgirardi avatar Jun 20 '22 22:06 dgirardi

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

lgtm-com[bot] avatar Jun 20 '22 22:06 lgtm-com[bot]

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.

dgirardi avatar Jun 21 '22 18:06 dgirardi

Should core import postscribe?

patmmccann avatar Jul 11 '22 15:07 patmmccann

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 avatar May 29 '23 21:05 nikpil93

@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.

dgirardi avatar May 30 '23 15:05 dgirardi