From 0756833f53c50c35a467a32b67aa0a0a80943199 2014-03-04 00:10:19 From: MinRK Date: 2014-03-04 00:10:19 Subject: [PATCH] sanitize CSS rather than removing it entirely --- diff --git a/IPython/html/static/base/js/security.js b/IPython/html/static/base/js/security.js index 3ccdeb6..e311146 100644 --- a/IPython/html/static/base/js/security.js +++ b/IPython/html/static/base/js/security.js @@ -42,6 +42,7 @@ IPython.security = (function (IPython) { if (window && window.html) { caja = window.html; caja.html4 = window.html4; + caja.sanitizeStylesheet = window.sanitizeStylesheet; } var sanitizeAttribs = function (tagName, attribs, opt_naiveUriRewriter, opt_nmTokenPolicy, opt_logger) { @@ -59,8 +60,37 @@ IPython.security = (function (IPython) { return caja.sanitizeAttribs(tagName, attribs, opt_naiveUriRewriter, opt_nmTokenPolicy, opt_logger); }; - var sanitize = function (html, log) { + var sanitize_css = function (css, tagPolicy) { + return caja.sanitizeStylesheet( + window.location.pathname, + css, + { + containerClass: null, + idSuffix: '', + tagPolicy: tagPolicy, + virtualizeAttrName: noop + }, + noop + ); + }; + + var sanitize_stylesheets = function (html, tagPolicy) { + var h = $("
").append(html); + var style_tags = h.find("style"); + if (!style_tags.length) { + // no style tags to sanitize + return html; + } + style_tags.each(function(i, style) { + style.innerHTML = sanitize_css(style.innerHTML, tagPolicy); + }); + return h.html(); + }; + + var sanitize = function (html, allow_css) { // sanitize HTML + // if allow_css is true (default), CSS is sanitized as well. + // otherwise, CSS elements and attributes are simply removed. // returns a struct of // { // src: original_html, @@ -69,6 +99,20 @@ IPython.security = (function (IPython) { // This is an incomplete indication, // only used to indicate whether further verification is necessary. // } + var html4 = caja.html4; + + if (allow_css === undefined) allow_css = true; + if (allow_css) { + // allow sanitization of style tags, + // not just scrubbing + html4.ELEMENTS.style &= ~html4.eflags.UNSAFE; + html4.ATTRIBS.style = html4.atype.STYLE; + } else { + // scrub all CSS + html4.ELEMENTS.style |= html4.eflags.UNSAFE; + html4.ATTRIBS.style = html4.atype.SCRIPT; + } + var result = { src : html, _maybe_safe : true @@ -78,7 +122,6 @@ IPython.security = (function (IPython) { result._maybe_safe = false; }; - var html4 = caja.html4; var policy = function (tagName, attribs) { if (!(html4.ELEMENTS[tagName] & html4.eflags.UNSAFE)) { return { @@ -92,8 +135,14 @@ IPython.security = (function (IPython) { }); } }; - + result.sanitized = caja.sanitizeWithPolicy(html, policy); + + if (allow_css) { + // sanitize style tags as stylesheets + result.sanitized = sanitize_stylesheets(result.sanitized, policy); + } + return result; }; @@ -104,6 +153,7 @@ IPython.security = (function (IPython) { var is_safe = function (html) { // just return bool for whether an HTML string is safe + // this is not currently used for anything other than tests. var result = sanitize(html); // caja can strip whole elements without logging, @@ -117,6 +167,7 @@ IPython.security = (function (IPython) { }; return { + caja: caja, is_safe: is_safe, sanitize: sanitize, sanitize_html: sanitize_html diff --git a/IPython/html/templates/notebook.html b/IPython/html/templates/notebook.html index 42f5424..2252496 100644 --- a/IPython/html/templates/notebook.html +++ b/IPython/html/templates/notebook.html @@ -291,7 +291,7 @@ class="notebook_app" {{super()}} - +