diff --git a/IPython/html/static/base/js/security.js b/IPython/html/static/base/js/security.js index 583ba0f..648cf03 100644 --- a/IPython/html/static/base/js/security.js +++ b/IPython/html/static/base/js/security.js @@ -19,24 +19,29 @@ IPython.security = (function (IPython) { // Is the html string safe against JavaScript based attacks. This // detects 1) black listed tags, 2) blacklisted attributes, 3) all // event attributes (onhover, onclick, etc.). - var black_tags = ['script', 'style']; + var black_tags = ['script', 'style', 'meta', 'iframe', 'embed']; var black_attrs = ['style']; var wrapped_html = '<div>'+html+'</div>'; - var e = $(wrapped_html); + // First try to parse the HTML. All invalid HTML is unsafe. + try { + var bad_elem = $(wrapped_html); + } catch (e) { + return false; + } var safe = true; // Detect black listed tags $.map(black_tags, function (tag, index) { - if (e.find(tag).length > 0) { + if (bad_elem.find(tag).length > 0) { safe = false; } }); // Detect black listed attributes $.map(black_attrs, function (attr, index) { - if (e.find('['+attr+']').length > 0) { + if (bad_elem.find('['+attr+']').length > 0) { safe = false; } }); - e.find('*').each(function (index) { + bad_elem.find('*').each(function (index) { $.map(utils.get_attr_names($(this)), function (attr, index) { if (attr.match('^on')) {safe = false;} }); diff --git a/IPython/html/tests/casperjs/test_cases/security.js b/IPython/html/tests/casperjs/test_cases/security.js new file mode 100644 index 0000000..5aa0b55 --- /dev/null +++ b/IPython/html/tests/casperjs/test_cases/security.js @@ -0,0 +1,35 @@ +safe_tests = [ + "<p>Hi there</p>", + '<h1 class="foo">Hi There!</h1>', + '<div><span>Hi There</span></div>' +]; + +unsafe_tests = [ + "<script>alert(999);</script>", + '<a onmouseover="alert(999)">999</a>', + '<a onmouseover=alert(999)>999</a>', + '<IMG """><SCRIPT>alert("XSS")</SCRIPT>">', + '<IMG SRC=# onmouseover="alert(999)">', + '<<SCRIPT>alert(999);//<</SCRIPT>', + '<SCRIPT SRC=http://ha.ckers.org/xss.js?< B >', + '<META HTTP-EQUIV="refresh" CONTENT="0;url=data:text/html base64,PHNjcmlwdD5hbGVydCgnWFNTJyk8L3NjcmlwdD4K">', + '<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>', + '<EMBED SRC="data:image/svg+xml;base64,PHN2ZyB4bWxuczpzdmc9Imh0dH A6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcv MjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hs aW5rIiB2ZXJzaW9uPSIxLjAiIHg9IjAiIHk9IjAiIHdpZHRoPSIxOTQiIGhlaWdodD0iMjAw IiBpZD0ieHNzIj48c2NyaXB0IHR5cGU9InRleHQvZWNtYXNjcmlwdCI+YWxlcnQoIlh TUyIpOzwvc2NyaXB0Pjwvc3ZnPg==" type="image/svg+xml" AllowScriptAccess="always"></EMBED>', +]; + +casper.notebook_test(function () { + this.each(safe_tests, function (self, item) { + var is_safe = self.evaluate(function (item) { + return IPython.security.is_safe(item); + }, item); + this.test.assert(is_safe, item); + }); + this.each(unsafe_tests, function (self, item) { + var is_safe = self.evaluate(function (item) { + return IPython.security.is_safe(item); + }, item); + this.test.assert(!is_safe, item); + }); +}); \ No newline at end of file