sanitize CSS

rather than removing it entirely
pull/37/head
MinRK 12 years ago
parent d7b1e8b45b
commit 4d35660f3c

@ -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 = $("<div/>").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

@ -291,7 +291,7 @@ class="notebook_app"
{{super()}}
<script src="{{ static_url("components/google-caja/google-caja/html-sanitizer-minified.js") }}" charset="utf-8"></script>
<script src="{{ static_url("components/google-caja/html-css-sanitizer-minified.js") }}" charset="utf-8"></script>
<script src="{{ static_url("components/codemirror/lib/codemirror.js") }}" charset="utf-8"></script>
<script type="text/javascript">
CodeMirror.modeURL = "{{ static_url("components/codemirror/mode/%N/%N.js", include_version=False) }}";

@ -3,6 +3,7 @@ safe_tests = [
'<h1 class="foo">Hi There!</h1>',
'<a data-cite="foo">citation</a>',
'<div><span>Hi There</span></div>',
'<style>div.foo { background: #ffff; }</style>',
];
unsafe_tests = [
@ -17,7 +18,7 @@ unsafe_tests = [
'<META HTTP-EQUIV="refresh" CONTENT="0; URL=http://;URL=javascript:alert(999);">',
'<IFRAME SRC="javascript:alert(999);"></IFRAME>',
'<IFRAME SRC=# onmouseover="alert(document.cookie)"></IFRAME>',
'<style type="text/css">div.foo { background: #ffff; }</style>',
'<style src="http://untrusted/style.css"></style>',
'<EMBED SRC="data:image/svg+xml;base64,PHN2ZyB4bWxuczpzdmc9Imh0dH A6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcv MjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hs aW5rIiB2ZXJzaW9uPSIxLjAiIHg9IjAiIHk9IjAiIHdpZHRoPSIxOTQiIGhlaWdodD0iMjAw IiBpZD0ieHNzIj48c2NyaXB0IHR5cGU9InRleHQvZWNtYXNjcmlwdCI+YWxlcnQoIlh TUyIpOzwvc2NyaXB0Pjwvc3ZnPg==" type="image/svg+xml" AllowScriptAccess="always"></EMBED>',
];
@ -26,6 +27,10 @@ casper.notebook_test(function () {
var is_safe = self.evaluate(function (item) {
return IPython.security.is_safe(item);
}, item);
var sanitized = self.evaluate(function (item) {
return IPython.security.sanitize_html(item);
}, item);
this.test.assert(is_safe, "Safe: " + item);
});
this.each(unsafe_tests, function (self, item) {

Loading…
Cancel
Save