7

i'm wondering how safe it is to use createHTMLDocument to do HTML sanitization. I've tried to implement it like this:

function sanitize(string) {
  var elm = document.implementation.createHTMLDocument().body;
  elm.innerHTML = string;
  // traverse and filter elm to only allow whitelisted elements and attributes
  // e.g. use https://github.com/gbirke/Sanitize.js
  var cleaned_fragment = whitelist_filter(elm);
  elm = document.implementation.createHTMLDocument().body;
  elm.appendChild(cleaned_fragment);

  return elm.innerHTML;
}

It seems to work fine with all XSS attacks i've throw at it (no script evaluation or requests triggered). But I got a feeling it might be a bad idea, im I missing something?

I've created a jsfiddle if someone wants to experiment.

  • Are you trusting a client side javascript to sanitize the HTML? If I were an attacker, I'd simply bypass the sanitization completely by not calling your function. Sanitization has to be done server-side. – John Deters Feb 5 '14 at 14:09
  • How would you bypass it? lets say this is a case where some client side javascript fetches from a server API that returns unsafe html that you would like to sanitize and insert into the page – Mattias Wadman Feb 5 '14 at 14:24
  • 2
    @JohnDeters That depends very much on the context. Html encoding can happen on the client a web application where javascript weaves the data into the html for displaying on the same machine. You could bypass it, but that'd be like a script kiddy who proudly hacks 127.0.0.1. – CodesInChaos Feb 5 '14 at 15:02
  • In the case I mention wouldn't a bug in a sanitized be equally bad either if it's done server or client side? – Mattias Wadman Feb 5 '14 at 15:05
  • Some libraries are made for that task, like DOMPurify. It use DOMParser, createHTMLDocument or toStaticHTML – mems May 17 '17 at 15:17
6

You should use the DOMParser to parse HTML when available, and only fall back to DOMImplementation.createHTMLDocument if the former is unavailable.

In Opera Presto, I observed network activity when I passed <img src=...> (but not <video>).
Internet Explorer 9- is worse: media, styles and event listeners will be activated with this method. IE10+ supports DOMParser, so if your audience uses IE10+, then you're safe.

| improve this answer | |
  • Thanks, did know about DOMParser. Ok good to know, i noticed that Chrome tries to fetch img tags even when in a detached dom tree but does not if in a new document. – Mattias Wadman Feb 5 '14 at 14:39
  • Did NOT know about* :) – Mattias Wadman Feb 5 '14 at 16:49
  • 1
    @MattiasWadman If you don't mind loosing lots of potentially dangerous tags and attributes, you could also try the global toStaticHTML method in IE 8 + 9. – Rob W Feb 5 '14 at 16:54
2

Refering innerHTML of generated HTMLElement causes mXSS - a kind of DOM based XSS.

e.g, the code following causes mXSS at IE.

var s = "<listing>&lt;img src=1 onerror=alert(1)&gt;</listing>";
var parser = new DOMParser();
var doc = parser.parseFromString( s, "text/html" );
div.innerHTML = doc.body.innerHTML;

therefore, you have to manipulate as HTMLElement, don't refer innerHTML.

div.appendChild( doc.body.childNodes[ 0 ] );

see http://utf-8.jp/public/20140807/shibuyaxss.pdf and http://utf-8.jp/public/rickdom/

| improve this answer | |
  • mXSS is really interesting and make you feel that html sanitize is a sad mess to deal with :) I guess server side sanitize is the only "sane" way but still really really hard and a never ending battle. – Mattias Wadman Sep 8 '14 at 14:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.