From 17df0f88489be6cd1ed65dfd9bbed3e9ece3fea4 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Sun, 18 Mar 2018 08:00:12 +0000 Subject: [PATCH] Disable jQuery prefilter specifically to parse sanitized HTML (#29) * Add and use sanitize_html_and_parse() function * Describe return type in doc comment * Reset htmlPrefilter even if parsing HTML fails * Return directly from try block * Move toinsert to inner scope --- notebook/static/base/js/security.js | 20 ++++++++++++++++++++ notebook/static/notebook/js/outputarea.js | 10 +++++++--- notebook/static/notebook/js/textcell.js | 6 ++---- 3 files changed, 29 insertions(+), 7 deletions(-) diff --git a/notebook/static/base/js/security.js b/notebook/static/base/js/security.js index 696361beb..195c0a5cb 100644 --- a/notebook/static/base/js/security.js +++ b/notebook/static/base/js/security.js @@ -122,9 +122,29 @@ define([ return sanitized; }; + + var sanitize_html_and_parse = function (html, allow_css) { + /** + * Sanitize HTML and parse it safely using jQuery. + * + * This disable's jQuery's html 'prefilter', which can make invalid + * HTML valid after the sanitizer has checked it. + * + * Returns an array of DOM nodes. + */ + var sanitized_html = sanitize_html(html, allow_css); + var prev_htmlPrefilter = $.htmlPrefilter; + $.htmlPrefilter = function(html) {return html;}; // Don't modify HTML + try { + return $.parseHTML(sanitized_html); + } finally { + $.htmlPrefilter = prev_htmlPrefilter; // Set it back again + } + }; var security = { caja: caja, + sanitize_html_and_parse: sanitize_html_and_parse, sanitize_html: sanitize_html }; diff --git a/notebook/static/notebook/js/outputarea.js b/notebook/static/notebook/js/outputarea.js index 219cee29f..8cffa32ba 100644 --- a/notebook/static/notebook/js/outputarea.js +++ b/notebook/static/notebook/js/outputarea.js @@ -674,19 +674,23 @@ define([ var type = OutputArea.display_order[i]; var append = OutputArea.append_map[type]; if ((json.data[type] !== undefined) && append) { + var md = json.metadata || {}; var value = json.data[type]; + var toinsert; if (!this.trusted && !OutputArea.safe_outputs[type]) { // not trusted, sanitize HTML if (type===MIME_HTML || type==='text/svg') { - value = security.sanitize_html(value); + var parsed = $(security.sanitize_html_and_parse(value)); + toinsert = append.apply(this, [parsed, md, element, handle_inserted]); } else { // don't display if we don't know how to sanitize it console.log("Ignoring untrusted " + type + " output."); continue; } + } else { + toinsert = append.apply(this, [value, md, element, handle_inserted]); } - var md = json.metadata || {}; - var toinsert = append.apply(this, [value, md, element, handle_inserted]); + // Since only the png and jpeg mime types call the inserted // callback, if the mime type is something other we must call the // inserted callback only when the element is actually inserted diff --git a/notebook/static/notebook/js/textcell.js b/notebook/static/notebook/js/textcell.js index 58ca9ca78..68124403c 100644 --- a/notebook/static/notebook/js/textcell.js +++ b/notebook/static/notebook/js/textcell.js @@ -248,8 +248,7 @@ define([ // HTML ) var text = this.get_text(); marked(text, function (err, html) { - html = security.sanitize_html(html); - html = $($.parseHTML(html)); + html = $(security.sanitize_html_and_parse(html)); html.find('img[src^="attachment:"]').each(function (i, h) { h = $(h); var key = h.attr('src').replace(/^attachment:/, ''); @@ -402,8 +401,7 @@ define([ }; marked(text, { renderer: renderer }, function (err, html) { html = mathjaxutils.replace_math(html, math); - html = security.sanitize_html(html); - html = $($.parseHTML(html)); + html = $(security.sanitize_html_and_parse(html)); // add anchors to headings html.find(":header").addBack(":header").each(function (i, h) { h = $(h);