From 9e2f251245cfbec2c55550fa3183d06d0cda7aff Mon Sep 17 00:00:00 2001 From: Jody McIntyre Date: Thu, 28 Jul 2016 20:44:10 -0400 Subject: [PATCH 1/3] HTML encode attributes in s and s I don't believe this is necessary for security, but it makes our code more obviously secure. --- src/lib/svg_text_utils.js | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/lib/svg_text_utils.js b/src/lib/svg_text_utils.js index 922c4b0213e..fe995cc74f7 100644 --- a/src/lib/svg_text_utils.js +++ b/src/lib/svg_text_utils.js @@ -242,6 +242,15 @@ util.plainText = function(_str) { return (_str || '').replace(STRIP_TAGS, ' '); }; +function encodeForHTML(_str) { + return (_str || '').replace(/&/g, '&') + .replace(//g, '>') + .replace(/"/g, '"') + .replace(/'/g, ''') + .replace(/\//g, '/'); +} + function convertToSVG(_str) { var htmlEntitiesDecoded = Plotly.util.html_entity_decode(_str); var result = htmlEntitiesDecoded @@ -270,15 +279,14 @@ function convertToSVG(_str) { // remove quotes, leading '=', replace '&' with '&' var href = extra.substr(4) .replace(/["']/g, '') - .replace(/=/, '') - .replace(/&/g, '&'); + .replace(/=/, ''); // check protocol var dummyAnchor = document.createElement('a'); dummyAnchor.href = href; if(PROTOCOLS.indexOf(dummyAnchor.protocol) === -1) return ''; - return ''; + return ''; } } else if(tag === 'br') return '
'; @@ -302,7 +310,7 @@ function convertToSVG(_str) { // most of the svg css users will care about is just like html, // but font color is different. Let our users ignore this. extraStyle = extraStyle[1].replace(/(^|;)\s*color:/, '$1 fill:'); - style = (style ? style + ';' : '') + extraStyle; + style = (style ? style + ';' : '') + encodeForHTML(extraStyle); } return tspanStart + (style ? ' style="' + style + '"' : '') + '>'; From 4e2761c14d65e27c9952b6e98f7963da5dd660c5 Mon Sep 17 00:00:00 2001 From: Jody McIntyre Date: Thu, 28 Jul 2016 20:45:24 -0400 Subject: [PATCH 2/3] Add tests of generation --- test/jasmine/tests/svg_text_utils_test.js | 50 +++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/test/jasmine/tests/svg_text_utils_test.js b/test/jasmine/tests/svg_text_utils_test.js index 6d11560a105..4ebbea59eb3 100644 --- a/test/jasmine/tests/svg_text_utils_test.js +++ b/test/jasmine/tests/svg_text_utils_test.js @@ -25,6 +25,11 @@ describe('svg+text utils', function() { expect(a.attr('xlink:show')).toBe(href === null ? null : 'new'); } + function assertTspanStyle(node, style) { + var tspan = node.select('tspan'); + expect(tspan.attr('style')).toBe(style); + } + function assertAnchorAttrs(node) { var a = node.select('a'); @@ -134,5 +139,50 @@ describe('svg+text utils', function() { assertAnchorLink(node, 'https://abc.com/myFeature.jsp?name=abc&pwd=def'); }); }); + + it('allow basic spans', function() { + var node = mockTextSVGElement( + 'text' + ); + + expect(node.text()).toEqual('text'); + assertTspanStyle(node, null); + }); + + it('ignore unquoted styles in spans', function() { + var node = mockTextSVGElement( + 'text' + ); + + expect(node.text()).toEqual('text'); + assertTspanStyle(node, null); + }); + + it('allow quoted styles in spans', function() { + var node = mockTextSVGElement( + 'text' + ); + + expect(node.text()).toEqual('text'); + assertTspanStyle(node, 'quoted: yeah;'); + }); + + it('ignore extra stuff after span styles', function() { + var node = mockTextSVGElement( + 'text' + ); + + expect(node.text()).toEqual('text'); + assertTspanStyle(node, 'quoted: yeah;'); + }); + + it('escapes HTML entities in span styles', function() { + var node = mockTextSVGElement( + 'text' + ); + + expect(node.text()).toEqual('text'); + assertTspanStyle(node, 'quoted: yeah&\';;'); + }); }); }); From 763485c7577ef2bcff156da46e3d71989d12fe3f Mon Sep 17 00:00:00 2001 From: Jody McIntyre Date: Thu, 28 Jul 2016 20:45:35 -0400 Subject: [PATCH 3/3] Add test that relative links work --- test/jasmine/tests/svg_text_utils_test.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/test/jasmine/tests/svg_text_utils_test.js b/test/jasmine/tests/svg_text_utils_test.js index 4ebbea59eb3..be4601743c8 100644 --- a/test/jasmine/tests/svg_text_utils_test.js +++ b/test/jasmine/tests/svg_text_utils_test.js @@ -80,6 +80,16 @@ describe('svg+text utils', function() { assertAnchorLink(node, null); }); + it('whitelist relative hrefs (interpreted as http)', function() { + var node = mockTextSVGElement( + '
mylink' + ); + + expect(node.text()).toEqual('mylink'); + assertAnchorAttrs(node); + assertAnchorLink(node, '/mylink'); + }); + it('whitelist http hrefs', function() { var node = mockTextSVGElement( 'bl.ocks.org'